You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by ra...@apache.org on 2021/02/10 09:41:35 UTC

[phoenix-omid] branch master updated: OMID-194 OmidTableManager cannot create commit and timestamp tables in kerberos cluster(Rajeshbabu)

This is an automated email from the ASF dual-hosted git repository.

rajeshbabu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/phoenix-omid.git


The following commit(s) were added to refs/heads/master by this push:
     new 86dcf1e  OMID-194 OmidTableManager cannot create commit and timestamp tables in kerberos cluster(Rajeshbabu)
86dcf1e is described below

commit 86dcf1e1d0d177af217838be7d951b58d783034d
Author: Rajeshbabu Chintaguntla <ra...@apache.org>
AuthorDate: Tue Feb 9 10:38:45 2021 +0530

    OMID-194 OmidTableManager cannot create commit and timestamp tables in kerberos cluster(Rajeshbabu)
---
 .../org/apache/omid/tools/hbase/HBaseLogin.java    | 90 +++++++++++++++++++---
 .../apache/omid/tools/hbase/OmidTableManager.java  |  7 +-
 2 files changed, 86 insertions(+), 11 deletions(-)

diff --git a/hbase-common/src/main/java/org/apache/omid/tools/hbase/HBaseLogin.java b/hbase-common/src/main/java/org/apache/omid/tools/hbase/HBaseLogin.java
index 92b4904..0241fc0 100644
--- a/hbase-common/src/main/java/org/apache/omid/tools/hbase/HBaseLogin.java
+++ b/hbase-common/src/main/java/org/apache/omid/tools/hbase/HBaseLogin.java
@@ -17,7 +17,11 @@
  */
 package org.apache.omid.tools.hbase;
 
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.HBaseConfiguration;
+import org.apache.hadoop.hbase.security.User;
 import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.hadoop.security.authentication.util.KerberosUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -29,22 +33,38 @@ public final class HBaseLogin {
     private static final Logger LOG = LoggerFactory.getLogger(HBaseLogin.class);
 
     private static volatile UserGroupInformation ugi;
+    private static final Object KERBEROS_LOGIN_LOCK = new Object();
 
     @Nullable
     public static UserGroupInformation loginIfNeeded(SecureHBaseConfig config) throws IOException {
+        return loginIfNeeded(config, null);
+    }
 
-        if (UserGroupInformation.isSecurityEnabled()) {
-            LOG.info("Security enabled when connecting to HBase");
-            if (ugi == null) { // Use lazy initialization with double-checked locking
-                synchronized (HBaseLogin.class) {
-                    if (ugi == null) {
-                        LOG.info("Login with Kerberos. User={}, keytab={}", config.getPrincipal(), config.getKeytab());
-                        UserGroupInformation.loginUserFromKeytab(config.getPrincipal(), config.getKeytab());
-                        ugi = UserGroupInformation.getCurrentUser();
+    @Nullable
+    public static UserGroupInformation loginIfNeeded(SecureHBaseConfig config, Configuration hbaseConf) throws IOException {
+        boolean credsProvided = null != config.getPrincipal() && null != config.getKeytab();
+        if (UserGroupInformation.isSecurityEnabled() && credsProvided) {
+            // Check if we need to authenticate with kerberos so that we cache the correct ConnectionInfo
+            UserGroupInformation currentUser = UserGroupInformation.getCurrentUser();
+            if (!currentUser.hasKerberosCredentials() || !isSameName(currentUser.getUserName(), config.getPrincipal())) {
+                synchronized (KERBEROS_LOGIN_LOCK) {
+                    // Double check the current user, might have changed since we checked last. Don't want
+                    // to re-login if it's the same user.
+                    currentUser = UserGroupInformation.getCurrentUser();
+                    if (!currentUser.hasKerberosCredentials() || !isSameName(currentUser.getUserName(), config.getPrincipal())) {
+                        final Configuration hbaseConfig = getConfiguration(hbaseConf, config.getPrincipal(), config.getKeytab());
+                        LOG.info("Trying to connect to a secure cluster as {} " +
+                                        "with keytab {}",
+                                hbaseConfig.get(SecureHBaseConfig.HBASE_CLIENT_PRINCIPAL_KEY),
+                                hbaseConfig.get(SecureHBaseConfig.HBASE_CLIENT_KEYTAB_KEY));
+                        UserGroupInformation.setConfiguration(hbaseConfig);
+                        User.login(hbaseConfig, SecureHBaseConfig.HBASE_CLIENT_KEYTAB_KEY, SecureHBaseConfig.HBASE_CLIENT_PRINCIPAL_KEY, null);
+                        LOG.info("Successful login to secure cluster");
                     }
                 }
             } else {
-                LOG.info("User {}, already trusted (Kerberos). Avoiding 2nd login as it causes problems", ugi.toString());
+                // The user already has Kerberos creds, so there isn't anything to change in the ConnectionInfo.
+                LOG.debug("Already logged in as {}", currentUser);
             }
         } else {
             LOG.warn("Security NOT enabled when connecting to HBase. Act at your own risk. NULL UGI returned");
@@ -52,4 +72,56 @@ public final class HBaseLogin {
         return ugi;
     }
 
+    static boolean isSameName(String currentName, String newName, String hostname, String defaultRealm) throws IOException {
+        final boolean newNameContainsRealm = newName.indexOf('@') != -1;
+        // Make sure to replace "_HOST" if it exists before comparing the principals.
+        if (newName.contains(org.apache.hadoop.security.SecurityUtil.HOSTNAME_PATTERN)) {
+            if (newNameContainsRealm) {
+                newName = org.apache.hadoop.security.SecurityUtil.getServerPrincipal(newName, hostname);
+            } else {
+                // If the principal ends with "/_HOST", replace "_HOST" with the hostname.
+                if (newName.endsWith("/_HOST")) {
+                    newName = newName.substring(0, newName.length() - 5) + hostname;
+                }
+            }
+        }
+        // The new name doesn't contain a realm and we could compute a default realm
+        if (!newNameContainsRealm && defaultRealm != null) {
+            return currentName.equals(newName + "@" + defaultRealm);
+        }
+        // We expect both names to contain a realm, so we can do a simple equality check
+        return currentName.equals(newName);
+    }
+
+    static boolean isSameName(String currentName, String newName) throws IOException {
+        return isSameName(currentName, newName, null, getDefaultKerberosRealm());
+    }
+
+    /**
+     * Computes the default kerberos realm if one is available. If one cannot be computed, null
+     * is returned.
+     *
+     * @return The default kerberos realm, or null.
+     */
+    static String getDefaultKerberosRealm() {
+        try {
+            return KerberosUtil.getDefaultRealm();
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    private static Configuration getConfiguration(Configuration conf, String principal, String keytab) {
+        if(conf == null) {
+            conf = HBaseConfiguration.create();
+        }
+        // Set the principal and keytab if provided from the URL (overriding those provided in Properties)
+        if (null != principal) {
+            conf.set(SecureHBaseConfig.HBASE_CLIENT_PRINCIPAL_KEY, principal);
+        }
+        if (null != keytab) {
+            conf.set(SecureHBaseConfig.HBASE_CLIENT_KEYTAB_KEY, keytab);
+        }
+        return conf;
+    }
 }
diff --git a/hbase-tools/src/main/java/org/apache/omid/tools/hbase/OmidTableManager.java b/hbase-tools/src/main/java/org/apache/omid/tools/hbase/OmidTableManager.java
index 8e25530..104f2e8 100644
--- a/hbase-tools/src/main/java/org/apache/omid/tools/hbase/OmidTableManager.java
+++ b/hbase-tools/src/main/java/org/apache/omid/tools/hbase/OmidTableManager.java
@@ -78,8 +78,11 @@ public class OmidTableManager {
     }
 
     public void executeActionsOnHBase(Configuration hbaseConf) throws IOException {
-
-        HBaseLogin.loginIfNeeded(mainConfig.loginFlags);
+        mainConfig.loginFlags.setPrincipal(
+                hbaseConf.get(SecureHBaseConfig.HBASE_CLIENT_PRINCIPAL_KEY));
+        mainConfig.loginFlags.setKeytab(
+                hbaseConf.get(SecureHBaseConfig.HBASE_CLIENT_KEYTAB_KEY));
+        HBaseLogin.loginIfNeeded(mainConfig.loginFlags, hbaseConf);
 
         try (Connection conn = ConnectionFactory.createConnection(hbaseConf);
              Admin hBaseAdmin = conn.getAdmin()) {