Author: garyh
Date: Mon Sep 12 19:59:17 2011
New Revision: 1169902
URL: http://svn.apache.org/viewvc?rev=1169902&view=rev
Log:
HBASE-4180 Check isSecurityEnabled before User.login for 0.21 compatibility
Added:
hbase/trunk/src/main/java/org/apache/hadoop/hbase/util/Methods.java
Modified:
hbase/trunk/CHANGES.txt
hbase/trunk/src/main/java/org/apache/hadoop/hbase/security/User.java
hbase/trunk/src/main/java/org/apache/hadoop/hbase/util/Classes.java
Modified: hbase/trunk/CHANGES.txt
URL:
http://svn.apache.org/viewvc/hbase/trunk/CHANGES.txt?rev=1169902&r1=1169901&r2=1169902&view=diff
==============================================================================
--- hbase/trunk/CHANGES.txt (original)
+++ hbase/trunk/CHANGES.txt Mon Sep 12 19:59:17 2011
@@ -567,6 +567,7 @@ Release 0.90.5 - Unreleased
(Gaojinchao)
HBASE-4294 HLogSplitter sleeps with 1-second granularity (todd)
HBASE-4270 IOE ignored during flush-on-close causes dataloss
+ HBASE-4180 HBase should check the isSecurityEnabled flag before login
IMPROVEMENT
HBASE-4205 Enhance HTable javadoc (Eric Charles)
Modified: hbase/trunk/src/main/java/org/apache/hadoop/hbase/security/User.java
URL:
http://svn.apache.org/viewvc/hbase/trunk/src/main/java/org/apache/hadoop/hbase/security/User.java?rev=1169902&r1=1169901&r2=1169902&view=diff
==============================================================================
--- hbase/trunk/src/main/java/org/apache/hadoop/hbase/security/User.java
(original)
+++ hbase/trunk/src/main/java/org/apache/hadoop/hbase/security/User.java Mon
Sep 12 19:59:17 2011
@@ -22,12 +22,13 @@ package org.apache.hadoop.hbase.security
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.util.Methods;
+import org.apache.hadoop.mapred.JobConf;
+import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.security.UserGroupInformation;
import java.io.IOException;
import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
import java.lang.reflect.UndeclaredThrowableException;
import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
@@ -43,15 +44,13 @@ import org.apache.commons.logging.Log;
* {@link org.apache.hadoop.security.UserGroupInformation} currently needed by
* HBase, but can be extended as needs change.
* </p>
- *
- * <p>
- * Note: this class does not attempt to support any of the Kerberos
- * authentication methods exposed in security-enabled Hadoop (for the moment
- * at least), as they're not yet needed. Properly supporting
- * authentication is left up to implementation in secure HBase.
- * </p>
*/
public abstract class User {
+ /**
+ * Flag to differentiate between API-incompatible changes to
+ * {@link org.apache.hadoop.security.UserGroupInformation} between vanilla
+ * Hadoop 0.20.x and secure Hadoop 0.20+.
+ */
private static boolean IS_SECURE_HADOOP = true;
static {
try {
@@ -144,6 +143,20 @@ public abstract class User {
}
}
+ /**
+ * Returns whether or not Kerberos authentication is configured. For
+ * non-secure Hadoop, this always returns <code>false</code>.
+ * For secure Hadoop, it will return the value from
+ * {@code UserGroupInformation.isSecurityEnabled()}.
+ */
+ public static boolean isSecurityEnabled() {
+ if (IS_SECURE_HADOOP) {
+ return SecureHadoopUser.isSecurityEnabled();
+ } else {
+ return HadoopUser.isSecurityEnabled();
+ }
+ }
+
/* Concrete implementations */
/**
@@ -230,6 +243,7 @@ public abstract class User {
return result;
}
+ /** @see User#createUserForTesting(org.apache.hadoop.conf.Configuration,
String, String[]) */
public static User createUserForTesting(Configuration conf,
String name, String[] groups) {
try {
@@ -258,10 +272,20 @@ public abstract class User {
}
}
+ /**
+ * No-op since we're running on a version of Hadoop that doesn't support
+ * logins.
+ * @see User#login(org.apache.hadoop.conf.Configuration, String, String,
String)
+ */
public static void login(Configuration conf, String fileConfKey,
String principalConfKey, String localhost) throws IOException {
LOG.info("Skipping login, not running on secure Hadoop");
}
+
+ /** Always returns {@code false}. */
+ public static boolean isSecurityEnabled() {
+ return false;
+ }
}
/**
@@ -331,6 +355,7 @@ public abstract class User {
}
}
+ /** @see User#createUserForTesting(org.apache.hadoop.conf.Configuration,
String, String[]) */
public static User createUserForTesting(Configuration conf,
String name, String[] groups) {
try {
@@ -347,27 +372,55 @@ public abstract class User {
}
}
+ /**
+ * Obtain credentials for the current process using the configured
+ * Kerberos keytab file and principal.
+ * @see User#login(org.apache.hadoop.conf.Configuration, String, String,
String)
+ *
+ * @param conf the Configuration to use
+ * @param fileConfKey Configuration property key used to store the path
+ * to the keytab file
+ * @param principalConfKey Configuration property key used to store the
+ * principal name to login as
+ * @param localhost the local hostname
+ */
public static void login(Configuration conf, String fileConfKey,
String principalConfKey, String localhost) throws IOException {
- // check for SecurityUtil class
+ if (isSecurityEnabled()) {
+ // check for SecurityUtil class
+ try {
+ Class c = Class.forName("org.apache.hadoop.security.SecurityUtil");
+ Class[] types = new Class[]{
+ Configuration.class, String.class, String.class, String.class };
+ Object[] args = new Object[]{
+ conf, fileConfKey, principalConfKey, localhost };
+ Methods.call(c, null, "login", types, args);
+ } catch (ClassNotFoundException cnfe) {
+ throw new RuntimeException("Unable to login using " +
+ "org.apache.hadoop.security.SecurityUtil.login(). SecurityUtil
class " +
+ "was not found! Is this a version of secure Hadoop?", cnfe);
+ } catch (IOException ioe) {
+ throw ioe;
+ } catch (RuntimeException re) {
+ throw re;
+ } catch (Exception e) {
+ throw new UndeclaredThrowableException(e,
+ "Unhandled exception in User.login()");
+ }
+ }
+ }
+
+ /**
+ * Returns the result of {@code UserGroupInformation.isSecurityEnabled()}.
+ */
+ public static boolean isSecurityEnabled() {
try {
- Class c = Class.forName("org.apache.hadoop.security.SecurityUtil");
- Class[] types = new Class[]{
- Configuration.class, String.class, String.class, String.class };
- Object[] args = new Object[]{
- conf, fileConfKey, principalConfKey, localhost };
- call(c, null, "login", types, args);
- } catch (ClassNotFoundException cnfe) {
- throw new RuntimeException("Unable to login using " +
- "org.apache.hadoop.security.Security.login(). SecurityUtil class "
+
- "was not found! Is this a version of secure Hadoop?", cnfe);
- } catch (IOException ioe) {
- throw ioe;
+ return (Boolean)callStatic("isSecurityEnabled");
} catch (RuntimeException re) {
throw re;
} catch (Exception e) {
throw new UndeclaredThrowableException(e,
- "Unhandled exception in User.login()");
+ "Unexpected exception calling
UserGroupInformation.isSecurityEnabled()");
}
}
}
@@ -384,54 +437,7 @@ public abstract class User {
private static Object call(UserGroupInformation instance, String methodName,
Class[] types, Object[] args) throws Exception {
- return call(UserGroupInformation.class, instance, methodName, types, args);
- }
-
- private static <T> Object call(Class<T> clazz, T instance, String methodName,
- Class[] types, Object[] args) throws Exception {
- try {
- Method m = clazz.getMethod(methodName, types);
- return m.invoke(instance, args);
- } catch (IllegalArgumentException arge) {
- LOG.fatal("Constructed invalid call. class="+clazz.getName()+
- " method=" + methodName + " types=" + stringify(types), arge);
- throw arge;
- } catch (NoSuchMethodException nsme) {
- throw new IllegalArgumentException(
- "Can't find method "+methodName+" in "+clazz.getName()+"!", nsme);
- } catch (InvocationTargetException ite) {
- // unwrap the underlying exception and rethrow
- if (ite.getTargetException() != null) {
- if (ite.getTargetException() instanceof Exception) {
- throw (Exception)ite.getTargetException();
- } else if (ite.getTargetException() instanceof Error) {
- throw (Error)ite.getTargetException();
- }
- }
- throw new UndeclaredThrowableException(ite,
- "Unknown exception invoking "+clazz.getName()+"."+methodName+"()");
- } catch (IllegalAccessException iae) {
- throw new IllegalArgumentException(
- "Denied access calling "+clazz.getName()+"."+methodName+"()", iae);
- } catch (SecurityException se) {
- LOG.fatal("SecurityException calling method. class="+clazz.getName()+
- " method=" + methodName + " types=" + stringify(types), se);
- throw se;
- }
- }
-
- private static String stringify(Class[] classes) {
- StringBuilder buf = new StringBuilder();
- if (classes != null) {
- for (Class c : classes) {
- if (buf.length() > 0) {
- buf.append(",");
- }
- buf.append(c.getName());
- }
- } else {
- buf.append("NULL");
- }
- return buf.toString();
+ return Methods.call(UserGroupInformation.class, instance, methodName,
types,
+ args);
}
}
Modified: hbase/trunk/src/main/java/org/apache/hadoop/hbase/util/Classes.java
URL:
http://svn.apache.org/viewvc/hbase/trunk/src/main/java/org/apache/hadoop/hbase/util/Classes.java?rev=1169902&r1=1169901&r2=1169902&view=diff
==============================================================================
--- hbase/trunk/src/main/java/org/apache/hadoop/hbase/util/Classes.java
(original)
+++ hbase/trunk/src/main/java/org/apache/hadoop/hbase/util/Classes.java Mon Sep
12 19:59:17 2011
@@ -1,3 +1,23 @@
+/*
+ * Copyright The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package org.apache.hadoop.hbase.util;
/**
@@ -41,4 +61,18 @@ public class Classes {
return valueType;
}
+ public static String stringify(Class[] classes) {
+ StringBuilder buf = new StringBuilder();
+ if (classes != null) {
+ for (Class c : classes) {
+ if (buf.length() > 0) {
+ buf.append(",");
+ }
+ buf.append(c.getName());
+ }
+ } else {
+ buf.append("NULL");
+ }
+ return buf.toString();
+ }
}
Added: hbase/trunk/src/main/java/org/apache/hadoop/hbase/util/Methods.java
URL:
http://svn.apache.org/viewvc/hbase/trunk/src/main/java/org/apache/hadoop/hbase/util/Methods.java?rev=1169902&view=auto
==============================================================================
--- hbase/trunk/src/main/java/org/apache/hadoop/hbase/util/Methods.java (added)
+++ hbase/trunk/src/main/java/org/apache/hadoop/hbase/util/Methods.java Mon Sep
12 19:59:17 2011
@@ -0,0 +1,65 @@
+/*
+ * Copyright The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.hbase.util;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.UndeclaredThrowableException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class Methods {
+ private static Log LOG = LogFactory.getLog(Methods.class);
+
+ public static <T> Object call(Class<T> clazz, T instance, String methodName,
+ Class[] types, Object[] args) throws Exception {
+ try {
+ Method m = clazz.getMethod(methodName, types);
+ return m.invoke(instance, args);
+ } catch (IllegalArgumentException arge) {
+ LOG.fatal("Constructed invalid call. class="+clazz.getName()+
+ " method=" + methodName + " types=" + Classes.stringify(types),
arge);
+ throw arge;
+ } catch (NoSuchMethodException nsme) {
+ throw new IllegalArgumentException(
+ "Can't find method "+methodName+" in "+clazz.getName()+"!", nsme);
+ } catch (InvocationTargetException ite) {
+ // unwrap the underlying exception and rethrow
+ if (ite.getTargetException() != null) {
+ if (ite.getTargetException() instanceof Exception) {
+ throw (Exception)ite.getTargetException();
+ } else if (ite.getTargetException() instanceof Error) {
+ throw (Error)ite.getTargetException();
+ }
+ }
+ throw new UndeclaredThrowableException(ite,
+ "Unknown exception invoking "+clazz.getName()+"."+methodName+"()");
+ } catch (IllegalAccessException iae) {
+ throw new IllegalArgumentException(
+ "Denied access calling "+clazz.getName()+"."+methodName+"()", iae);
+ } catch (SecurityException se) {
+ LOG.fatal("SecurityException calling method. class="+clazz.getName()+
+ " method=" + methodName + " types=" + Classes.stringify(types), se);
+ throw se;
+ }
+ }
+}