You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by ap...@apache.org on 2020/10/29 21:24:44 UTC
[hbase] branch branch-1 updated: HBASE-24768 Clear cached service
kerberos ticket in case of SASL failures (#2578)
This is an automated email from the ASF dual-hosted git repository.
apurtell pushed a commit to branch branch-1
in repository https://gitbox.apache.org/repos/asf/hbase.git
The following commit(s) were added to refs/heads/branch-1 by this push:
new 0b48208 HBASE-24768 Clear cached service kerberos ticket in case of SASL failures (#2578)
0b48208 is described below
commit 0b48208bd54bb201c6103c195146727ed000a9da
Author: sguggilam <sa...@gmail.com>
AuthorDate: Thu Oct 29 14:23:52 2020 -0700
HBASE-24768 Clear cached service kerberos ticket in case of SASL failures (#2578)
Signed-off-by: Aman Poonia <am...@gmail.com>
Signed-off-by: Andrew Purtell <ap...@apache.org>
---
.../org/apache/hadoop/hbase/ipc/RpcConnection.java | 71 +++++++++++++++++++++-
.../java/org/apache/hadoop/hbase/HConstants.java | 14 +++++
2 files changed, 83 insertions(+), 2 deletions(-)
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/ipc/RpcConnection.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/ipc/RpcConnection.java
index 5e9e97e..d39013b 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/ipc/RpcConnection.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/ipc/RpcConnection.java
@@ -22,6 +22,8 @@ import io.netty.util.Timeout;
import io.netty.util.TimerTask;
import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.net.UnknownHostException;
import java.util.concurrent.TimeUnit;
@@ -45,6 +47,7 @@ import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.security.token.Token;
import org.apache.hadoop.security.token.TokenIdentifier;
import org.apache.hadoop.security.token.TokenSelector;
+import org.apache.hadoop.util.Time;
/**
* Base class for ipc connection.
@@ -75,6 +78,14 @@ abstract class RpcConnection {
// the last time we were picked up from connection pool.
protected long lastTouched;
+ // Determines whether we need to do an explicit clearing of kerberos tickets with relogin
+ private boolean forceReloginEnabled;
+ // Minimum time between two force re-login attempts
+ private int minTimeBeforeForceRelogin;
+
+ // Time when last forceful re-login was attempted
+ private long lastForceReloginAttempt = -1;
+
protected RpcConnection(Configuration conf, HashedWheelTimer timeoutTimer, ConnectionId remoteId,
String clusterId, boolean isSecurityEnabled, Codec codec, CompressionCodec compressor)
throws IOException {
@@ -126,8 +137,14 @@ abstract class RpcConnection {
LOG.debug("Use " + authMethod + " authentication for service " + remoteId.serviceName
+ ", sasl=" + useSasl);
}
- reloginMaxBackoff = conf.getInt("hbase.security.relogin.maxbackoff", 5000);
+
+ reloginMaxBackoff = conf.getInt(HConstants.HBASE_RELOGIN_MAXBACKOFF, 5000);
this.remoteId = remoteId;
+
+ forceReloginEnabled = conf.getBoolean(HConstants.HBASE_FORCE_RELOGIN_ENABLED, true);
+ // Default minimum time between force relogin attempts is 10 minutes
+ this.minTimeBeforeForceRelogin =
+ conf.getInt(HConstants.HBASE_MINTIME_BEFORE_FORCE_RELOGIN, 10 * 60 * 1000);
}
private UserInformation getUserInfo(UserGroupInformation ugi) {
@@ -173,12 +190,62 @@ abstract class RpcConnection {
protected void relogin() throws IOException {
if (UserGroupInformation.isLoginKeytabBased()) {
- UserGroupInformation.getLoginUser().reloginFromKeytab();
+ if (shouldForceRelogin()) {
+ LOG.debug(
+ "SASL Authentication failure. Attempting a forceful re-login for "
+ + UserGroupInformation.getLoginUser().getUserName());
+ Method logoutUserFromKeytab;
+ Method forceReloginFromKeytab;
+ try {
+ logoutUserFromKeytab = UserGroupInformation.class.getMethod("logoutUserFromKeytab");
+ forceReloginFromKeytab = UserGroupInformation.class.getMethod("forceReloginFromKeytab");
+ } catch (NoSuchMethodException e) {
+ // This shouldn't happen as we already check for the existence of these methods before
+ // entering this block
+ throw new RuntimeException("Cannot find forceReloginFromKeytab method in UGI");
+ }
+ logoutUserFromKeytab.setAccessible(true);
+ forceReloginFromKeytab.setAccessible(true);
+ try {
+ logoutUserFromKeytab.invoke(UserGroupInformation.getLoginUser());
+ forceReloginFromKeytab.invoke(UserGroupInformation.getLoginUser());
+ } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+ throw new RuntimeException(e.getCause());
+ }
+ } else {
+ UserGroupInformation.getLoginUser().reloginFromKeytab();
+ }
} else {
UserGroupInformation.getLoginUser().reloginFromTicketCache();
}
}
+ private boolean shouldForceRelogin() {
+ if (!forceReloginEnabled) {
+ return false;
+ }
+ long now = Time.now();
+ // If the last force relogin attempted is less than the configured minimum time, revert to the
+ // default relogin method of UGI
+ if (lastForceReloginAttempt != -1
+ && (now - lastForceReloginAttempt < minTimeBeforeForceRelogin)) {
+ LOG.debug("Not attempting to force re-login since the last attempt is less than "
+ + minTimeBeforeForceRelogin + " millis");
+ return false;
+ }
+ try {
+ // Check if forceRelogin method is available in UGI using reflection
+ UserGroupInformation.class.getMethod("forceReloginFromKeytab");
+ UserGroupInformation.class.getMethod("logoutUserFromKeytab");
+ } catch (NoSuchMethodException e) {
+ LOG.debug(
+ "forceReloginFromKeytab method not available in UGI. Skipping to attempt force relogin");
+ return false;
+ }
+ lastForceReloginAttempt = now;
+ return true;
+ }
+
protected void scheduleTimeoutTask(final Call call) {
if (call.timeout > 0) {
call.timeoutTask = timeoutTimer.newTimeout(new TimerTask() {
diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/HConstants.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/HConstants.java
index e660fe3..c1d688e 100644
--- a/hbase-common/src/main/java/org/apache/hadoop/hbase/HConstants.java
+++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/HConstants.java
@@ -321,6 +321,19 @@ public final class HConstants {
public static final String HBASE_CLIENT_META_OPERATION_TIMEOUT =
"hbase.client.meta.operation.timeout";
+ /** Parameter name for HBase client max backoff across SASL relogin failure retries */
+ public static final String HBASE_RELOGIN_MAXBACKOFF = "hbase.security.relogin.maxbackoff";
+
+ /** Parameter name for HBase client minimum time between forceful relogin attempts */
+ public static final String HBASE_MINTIME_BEFORE_FORCE_RELOGIN =
+ "hbase.mintime.before.force.relogin";
+
+ /**
+ * Whether forceful relogin (explicit clearing of kerberos tickets) is enabled on SASL
+ * Authentication failure
+ */
+ public static final String HBASE_FORCE_RELOGIN_ENABLED = "hbase.security.force.relogin.enabled";
+
/** Default HBase client operation timeout, which is tantamount to a blocking call */
public static final int DEFAULT_HBASE_CLIENT_OPERATION_TIMEOUT = 1200000;
@@ -331,6 +344,7 @@ public final class HConstants {
/** Default HBase client meta replica scan call timeout, 1 second */
public static final int HBASE_CLIENT_META_REPLICA_SCAN_TIMEOUT_DEFAULT = 1000000;
+
/** Used to construct the name of the log directory for a region server */
public static final String HREGION_LOGDIR_NAME = "WALs";