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

exceptionfactory pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git


The following commit(s) were added to refs/heads/main by this push:
     new e436381  NIFI-8975 Integrate KerberosUserService into HBase 
processors/services
e436381 is described below

commit e436381c3afb9585c8c6299eddb1e71dcb7666f1
Author: Bryan Bende <[email protected]>
AuthorDate: Fri Aug 20 12:56:34 2021 -0400

    NIFI-8975 Integrate KerberosUserService into HBase processors/services
    
    This closes #5322
    
    Signed-off-by: David Handermann <[email protected]>
---
 .../nifi/security/krb/KerberosLoginException.java  |  32 ++++++
 .../org/apache/nifi/security/krb/KerberosUser.java |  13 +--
 .../nifi/security/krb/AbstractKerberosUser.java    |  20 ++--
 .../apache/nifi/security/krb/KerberosAction.java   |   9 +-
 .../java/org/apache/nifi/hadoop/SecurityUtil.java  |  44 +++++---
 .../processors/hadoop/AbstractHadoopProcessor.java |  19 +---
 .../nifi-hbase-processors/pom.xml                  |   5 +-
 .../org/apache/nifi/hbase/AbstractPutHBase.java    |   8 +-
 .../apache/nifi/dbcp/hive/HiveConnectionPool.java  |   4 +-
 .../nifi/processors/hive/PutHiveStreaming.java     |   4 +-
 .../apache/nifi/dbcp/hive/Hive3ConnectionPool.java |   4 +-
 .../nifi/processors/hive/PutHive3Streaming.java    |   4 +-
 .../nifi/dbcp/hive/Hive_1_1ConnectionPool.java     |   4 +-
 .../processors/kudu/AbstractKuduProcessor.java     |   4 +-
 .../apache/nifi/processors/solr/SolrProcessor.java |   4 +-
 .../org/apache/nifi/dbcp/DBCPConnectionPool.java   |   5 +-
 .../apache/nifi/dbcp/GroovyDBCPServiceTest.groovy  |  14 +--
 .../apache/nifi/dbcp/HadoopDBCPConnectionPool.java |   5 +-
 .../nifi-hbase_1_1_2-client-service/pom.xml        |   6 +-
 .../nifi/hbase/HBase_1_1_2_ClientService.java      | 117 ++++++++++++++------
 .../nifi/hbase/TestHBase_1_1_2_ClientService.java  |  78 +++++++++++++
 .../nifi-hbase_2-client-service/pom.xml            |   7 +-
 .../apache/nifi/hbase/HBase_2_ClientService.java   | 121 +++++++++++++++------
 .../nifi/hbase/TestHBase_2_ClientService.java      |  78 +++++++++++++
 .../hortonworks/KerberosUserLogin.java             |   2 +-
 .../SchemaRegistryClientWithKerberosPassword.java  |   3 +-
 26 files changed, 452 insertions(+), 162 deletions(-)

diff --git 
a/nifi-commons/nifi-security-kerberos-api/src/main/java/org/apache/nifi/security/krb/KerberosLoginException.java
 
b/nifi-commons/nifi-security-kerberos-api/src/main/java/org/apache/nifi/security/krb/KerberosLoginException.java
new file mode 100644
index 0000000..f064d33
--- /dev/null
+++ 
b/nifi-commons/nifi-security-kerberos-api/src/main/java/org/apache/nifi/security/krb/KerberosLoginException.java
@@ -0,0 +1,32 @@
+/*
+ * 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.nifi.security.krb;
+
+/**
+ * Exception thrown by KerberosUser when an error happens during login/logout.
+ */
+public class KerberosLoginException extends RuntimeException {
+
+    public KerberosLoginException(String message) {
+        super(message);
+    }
+
+    public KerberosLoginException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+}
diff --git 
a/nifi-commons/nifi-security-kerberos-api/src/main/java/org/apache/nifi/security/krb/KerberosUser.java
 
b/nifi-commons/nifi-security-kerberos-api/src/main/java/org/apache/nifi/security/krb/KerberosUser.java
index 631f445..f6b0f35 100644
--- 
a/nifi-commons/nifi-security-kerberos-api/src/main/java/org/apache/nifi/security/krb/KerberosUser.java
+++ 
b/nifi-commons/nifi-security-kerberos-api/src/main/java/org/apache/nifi/security/krb/KerberosUser.java
@@ -17,7 +17,6 @@
 package org.apache.nifi.security.krb;
 
 import javax.security.auth.login.AppConfigurationEntry;
-import javax.security.auth.login.LoginException;
 import java.security.PrivilegedAction;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
@@ -30,16 +29,16 @@ public interface KerberosUser {
     /**
      * Performs a login for the given user.
      *
-     * @throws LoginException if the login fails
+     * @throws KerberosLoginException if the login fails
      */
-    void login() throws LoginException;
+    void login();
 
     /**
      * Performs a logout for the given user.
      *
-     * @throws LoginException if the logout fails
+     * @throws KerberosLoginException if the logout fails
      */
-    void logout() throws LoginException;
+    void logout();
 
     /**
      * Executes the given action as the given user.
@@ -107,9 +106,9 @@ public interface KerberosUser {
      * Performs a re-login if the TGT is close to expiration.
      *
      * @return true if a relogin was performed, false otherwise
-     * @throws LoginException if the relogin fails
+     * @throws KerberosLoginException if the relogin fails
      */
-    boolean checkTGTAndRelogin() throws LoginException;
+    boolean checkTGTAndRelogin();
 
     /**
      * @return true if this user is currently logged in, false otherwise
diff --git 
a/nifi-commons/nifi-security-kerberos/src/main/java/org/apache/nifi/security/krb/AbstractKerberosUser.java
 
b/nifi-commons/nifi-security-kerberos/src/main/java/org/apache/nifi/security/krb/AbstractKerberosUser.java
index 3d7c96c..6fe46b6 100644
--- 
a/nifi-commons/nifi-security-kerberos/src/main/java/org/apache/nifi/security/krb/AbstractKerberosUser.java
+++ 
b/nifi-commons/nifi-security-kerberos/src/main/java/org/apache/nifi/security/krb/AbstractKerberosUser.java
@@ -75,10 +75,10 @@ public abstract class AbstractKerberosUser implements 
KerberosUser {
     /**
      * Performs a login using the specified principal and keytab.
      *
-     * @throws LoginException if the login fails
+     * @throws KerberosLoginException if the login fails
      */
     @Override
-    public synchronized void login() throws LoginException {
+    public synchronized void login() {
         if (isLoggedIn()) {
             return;
         }
@@ -100,10 +100,8 @@ public abstract class AbstractKerberosUser implements 
KerberosUser {
             loginContext.login();
             loggedIn.set(true);
             LOGGER.debug("Successful login for {}", new Object[]{principal});
-        } catch (LoginException le) {
-            LoginException loginException = new LoginException("Unable to 
login with " + principal + " due to: " + le.getMessage());
-            loginException.setStackTrace(le.getStackTrace());
-            throw loginException;
+        } catch (final LoginException le) {
+            throw new KerberosLoginException("Unable to login with " + 
principal + " due to: " + le.getMessage(), le);
         }
     }
 
@@ -134,10 +132,10 @@ public abstract class AbstractKerberosUser implements 
KerberosUser {
     /**
      * Performs a logout of the current user.
      *
-     * @throws LoginException if the logout fails
+     * @throws KerberosLoginException if the logout fails
      */
     @Override
-    public synchronized void logout() throws LoginException {
+    public synchronized void logout() {
         if (!isLoggedIn()) {
             return;
         }
@@ -148,8 +146,8 @@ public abstract class AbstractKerberosUser implements 
KerberosUser {
             LOGGER.debug("Successful logout for {}", new Object[]{principal});
 
             loginContext = null;
-        } catch (LoginException e) {
-            throw new LoginException("Logout failed due to: " + 
e.getMessage());
+        } catch (final LoginException e) {
+            throw new KerberosLoginException("Logout failed due to: " + 
e.getMessage(), e);
         }
     }
 
@@ -195,7 +193,7 @@ public abstract class AbstractKerberosUser implements 
KerberosUser {
      * @throws LoginException if an error happens performing the re-login
      */
     @Override
-    public synchronized boolean checkTGTAndRelogin() throws LoginException {
+    public synchronized boolean checkTGTAndRelogin()  {
         final KerberosTicket tgt = getTGT();
         if (tgt == null) {
             LOGGER.debug("TGT for {} was not found, performing logout/login", 
principal);
diff --git 
a/nifi-commons/nifi-security-kerberos/src/main/java/org/apache/nifi/security/krb/KerberosAction.java
 
b/nifi-commons/nifi-security-kerberos/src/main/java/org/apache/nifi/security/krb/KerberosAction.java
index dce2e06..ee1bfbf 100644
--- 
a/nifi-commons/nifi-security-kerberos/src/main/java/org/apache/nifi/security/krb/KerberosAction.java
+++ 
b/nifi-commons/nifi-security-kerberos/src/main/java/org/apache/nifi/security/krb/KerberosAction.java
@@ -20,7 +20,6 @@ import org.apache.commons.lang3.Validate;
 import org.apache.nifi.logging.ComponentLog;
 import org.apache.nifi.processor.exception.ProcessException;
 
-import javax.security.auth.login.LoginException;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
 
@@ -60,7 +59,7 @@ public class KerberosAction<T> {
             try {
                 kerberosUser.login();
                 logger.info("Successful login for {}", new 
Object[]{kerberosUser.getPrincipal()});
-            } catch (LoginException e) {
+            } catch (final KerberosLoginException e) {
                 throw new ProcessException("Login failed due to: " + 
e.getMessage(), e);
             }
         }
@@ -68,7 +67,7 @@ public class KerberosAction<T> {
         // check if we need to re-login, will only happen if re-login window 
is reached (80% of TGT life)
         try {
             kerberosUser.checkTGTAndRelogin();
-        } catch (LoginException e) {
+        } catch (final KerberosLoginException e) {
             throw new ProcessException("Relogin check failed due to: " + 
e.getMessage(), e);
         }
 
@@ -79,7 +78,7 @@ public class KerberosAction<T> {
             } else {
                 result = kerberosUser.doAs(action, contextClassLoader);
             }
-        } catch (SecurityException se) {
+        } catch (final SecurityException se) {
             logger.info("Privileged action failed, attempting relogin and 
retrying...");
             logger.debug("", se);
 
@@ -90,7 +89,7 @@ public class KerberosAction<T> {
             } catch (Exception e) {
                 throw new ProcessException("Retrying privileged action failed 
due to: " + e.getMessage(), e);
             }
-        } catch (PrivilegedActionException pae) {
+        } catch (final PrivilegedActionException pae) {
             final Exception cause = pae.getException();
             throw new ProcessException("Privileged action failed due to: " + 
cause.getMessage(), cause);
         }
diff --git 
a/nifi-nar-bundles/nifi-extension-utils/nifi-hadoop-utils/src/main/java/org/apache/nifi/hadoop/SecurityUtil.java
 
b/nifi-nar-bundles/nifi-extension-utils/nifi-hadoop-utils/src/main/java/org/apache/nifi/hadoop/SecurityUtil.java
index 6bf0aa5..0a9c023 100644
--- 
a/nifi-nar-bundles/nifi-extension-utils/nifi-hadoop-utils/src/main/java/org/apache/nifi/hadoop/SecurityUtil.java
+++ 
b/nifi-nar-bundles/nifi-extension-utils/nifi-hadoop-utils/src/main/java/org/apache/nifi/hadoop/SecurityUtil.java
@@ -20,12 +20,11 @@ import org.apache.commons.lang3.Validate;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.security.UserGroupInformation;
 import org.apache.nifi.logging.ComponentLog;
-import org.apache.nifi.processor.exception.ProcessException;
+import org.apache.nifi.security.krb.KerberosLoginException;
 import org.apache.nifi.security.krb.KerberosUser;
 
 import javax.security.auth.Subject;
 import javax.security.auth.kerberos.KerberosPrincipal;
-import javax.security.auth.login.LoginException;
 import java.io.IOException;
 import java.security.AccessControlContext;
 import java.security.AccessController;
@@ -110,9 +109,9 @@ public class SecurityUtil {
                 UserGroupInformation.setLoginUser(ugi);
                 return ugi;
             });
-        } catch (PrivilegedActionException e) {
+        } catch (final PrivilegedActionException e) {
             throw new IOException("Unable to acquire UGI for KerberosUser: " + 
e.getException().getLocalizedMessage(), e.getException());
-        } catch (LoginException e) {
+        } catch (final KerberosLoginException e) {
             throw new IOException("Unable to acquire UGI for KerberosUser: " + 
e.getLocalizedMessage(), e);
         }
     }
@@ -149,7 +148,16 @@ public class SecurityUtil {
         return 
KERBEROS.equalsIgnoreCase(config.get(HADOOP_SECURITY_AUTHENTICATION));
     }
 
-    public static <T> T callWithUgi(UserGroupInformation ugi, 
PrivilegedExceptionAction<T> action) throws IOException {
+    /**
+     * Helper method to execute the given action as the given user.
+     *
+     * @param ugi the user
+     * @param action the action
+     * @param <T> the result type of the action
+     * @return the result of the action
+     * @throws IOException if the action was interrupted
+     */
+    public static <T> T callWithUgi(final UserGroupInformation ugi, final 
PrivilegedExceptionAction<T> action) throws IOException {
         try {
             T result;
             if (ugi == null) {
@@ -171,19 +179,21 @@ public class SecurityUtil {
         }
     }
 
-    public static void checkTGTAndRelogin(ComponentLog log, KerberosUser 
kerberosUser) {
-        log.trace("getting UGI instance");
-        if (kerberosUser != null) {
-            // if there's a KerberosUser associated with this UGI, check the 
TGT and relogin if it is close to expiring
-            log.debug("kerberosUser is " + kerberosUser);
-            try {
-                log.debug("checking TGT on kerberosUser " + kerberosUser);
-                kerberosUser.checkTGTAndRelogin();
-            } catch (LoginException e) {
-                throw new ProcessException("Unable to relogin with kerberos 
credentials for " + kerberosUser.getPrincipal(), e);
-            }
-        } else {
+    /**
+     * Helper method to call checkTGTAndRelogin on a given KerberosUser that 
may be null.
+     *
+     * @param log the logger
+     * @param kerberosUser the kerberos user
+     * @throws KerberosLoginException if an error occurs when 
checkTGTAndRelogin calls login or logout
+     */
+    public static void checkTGTAndRelogin(final ComponentLog log, final 
KerberosUser kerberosUser) {
+        if (kerberosUser == null) {
             log.debug("kerberosUser was null, will not refresh TGT with 
KerberosUser");
+            return;
         }
+
+        log.debug("checking TGT on kerberosUser {}", kerberosUser);
+        kerberosUser.checkTGTAndRelogin();
     }
+
 }
diff --git 
a/nifi-nar-bundles/nifi-extension-utils/nifi-hadoop-utils/src/main/java/org/apache/nifi/processors/hadoop/AbstractHadoopProcessor.java
 
b/nifi-nar-bundles/nifi-extension-utils/nifi-hadoop-utils/src/main/java/org/apache/nifi/processors/hadoop/AbstractHadoopProcessor.java
index 2aebf83..fd8dd4d 100644
--- 
a/nifi-nar-bundles/nifi-extension-utils/nifi-hadoop-utils/src/main/java/org/apache/nifi/processors/hadoop/AbstractHadoopProcessor.java
+++ 
b/nifi-nar-bundles/nifi-extension-utils/nifi-hadoop-utils/src/main/java/org/apache/nifi/processors/hadoop/AbstractHadoopProcessor.java
@@ -43,14 +43,12 @@ import org.apache.nifi.kerberos.KerberosUserService;
 import org.apache.nifi.processor.AbstractProcessor;
 import org.apache.nifi.processor.ProcessContext;
 import org.apache.nifi.processor.ProcessorInitializationContext;
-import org.apache.nifi.processor.exception.ProcessException;
 import org.apache.nifi.processor.util.StandardValidators;
 import org.apache.nifi.security.krb.KerberosKeytabUser;
 import org.apache.nifi.security.krb.KerberosPasswordUser;
 import org.apache.nifi.security.krb.KerberosUser;
 
 import javax.net.SocketFactory;
-import javax.security.auth.login.LoginException;
 import java.io.File;
 import java.io.IOException;
 import java.lang.reflect.Field;
@@ -360,7 +358,7 @@ public abstract class AbstractHadoopProcessor extends 
AbstractProcessor {
             if (kerberosUser != null) {
                 try {
                     kerberosUser.logout();
-                } catch (LoginException e) {
+                } catch (final Exception e) {
                     getLogger().warn("Error logging out KerberosUser: {}", 
e.getMessage(), e);
                 }
             }
@@ -623,19 +621,8 @@ public abstract class AbstractHadoopProcessor extends 
AbstractProcessor {
 
     protected UserGroupInformation getUserGroupInformation() {
         getLogger().trace("getting UGI instance");
-        if (hdfsResources.get().getKerberosUser() != null) {
-            // if there's a KerberosUser associated with this UGI, check the 
TGT and relogin if it is close to expiring
-            KerberosUser kerberosUser = hdfsResources.get().getKerberosUser();
-            getLogger().debug("kerberosUser is " + kerberosUser);
-            try {
-                getLogger().debug("checking TGT on kerberosUser " + 
kerberosUser);
-                kerberosUser.checkTGTAndRelogin();
-            } catch (LoginException e) {
-                throw new ProcessException("Unable to relogin with kerberos 
credentials for " + kerberosUser.getPrincipal(), e);
-            }
-        } else {
-            getLogger().debug("kerberosUser was null, will not refresh TGT 
with KerberosUser");
-        }
+        // if there is a KerberosUser associated with UGI, call 
checkTGTAndRelogin to ensure UGI's underlying Subject has a valid ticket
+        SecurityUtil.checkTGTAndRelogin(getLogger(), 
hdfsResources.get().getKerberosUser());
         return hdfsResources.get().getUserGroupInformation();
     }
 
diff --git a/nifi-nar-bundles/nifi-hbase-bundle/nifi-hbase-processors/pom.xml 
b/nifi-nar-bundles/nifi-hbase-bundle/nifi-hbase-processors/pom.xml
index 13fc17f..45dcc9b 100644
--- a/nifi-nar-bundles/nifi-hbase-bundle/nifi-hbase-processors/pom.xml
+++ b/nifi-nar-bundles/nifi-hbase-bundle/nifi-hbase-processors/pom.xml
@@ -31,8 +31,11 @@
         </dependency>
         <dependency>
             <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-security-kerberos-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
             <artifactId>nifi-distributed-cache-client-service-api</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.nifi</groupId>
diff --git 
a/nifi-nar-bundles/nifi-hbase-bundle/nifi-hbase-processors/src/main/java/org/apache/nifi/hbase/AbstractPutHBase.java
 
b/nifi-nar-bundles/nifi-hbase-bundle/nifi-hbase-processors/src/main/java/org/apache/nifi/hbase/AbstractPutHBase.java
index d5c9acc..614b20d 100644
--- 
a/nifi-nar-bundles/nifi-hbase-bundle/nifi-hbase-processors/src/main/java/org/apache/nifi/hbase/AbstractPutHBase.java
+++ 
b/nifi-nar-bundles/nifi-hbase-bundle/nifi-hbase-processors/src/main/java/org/apache/nifi/hbase/AbstractPutHBase.java
@@ -32,6 +32,7 @@ import org.apache.nifi.processor.ProcessSession;
 import org.apache.nifi.processor.Relationship;
 import org.apache.nifi.processor.exception.ProcessException;
 import org.apache.nifi.processor.util.StandardValidators;
+import org.apache.nifi.security.krb.KerberosLoginException;
 
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
@@ -221,9 +222,11 @@ public abstract class AbstractPutHBase extends 
AbstractProcessor {
             try {
                 clientService.put(entry.getKey(), entry.getValue());
                 successes.addAll(entry.getValue());
-            } catch (Exception e) {
+            } catch (final KerberosLoginException kle) {
+                getLogger().error("Failed to connect to HBase due to {}: 
Rolling back session, and penalizing flow files", kle, kle);
+                session.rollback(true);
+            } catch (final Exception e) {
                 getLogger().error(e.getMessage(), e);
-
                 for (PutFlowFile putFlowFile : entry.getValue()) {
                     getLogger().error("Failed to send {} to HBase due to {}; 
routing to failure", new Object[]{putFlowFile.getFlowFile(), e});
                     final FlowFile failure = 
session.penalize(putFlowFile.getFlowFile());
@@ -240,7 +243,6 @@ public abstract class AbstractPutHBase extends 
AbstractProcessor {
             final String details = "Put " + putFlowFile.getColumns().size() + 
" cells to HBase";
             session.getProvenanceReporter().send(putFlowFile.getFlowFile(), 
getTransitUri(putFlowFile), details, sendMillis);
         }
-
     }
 
     protected String getTransitUri(PutFlowFile putFlowFile) {
diff --git 
a/nifi-nar-bundles/nifi-hive-bundle/nifi-hive-processors/src/main/java/org/apache/nifi/dbcp/hive/HiveConnectionPool.java
 
b/nifi-nar-bundles/nifi-hive-bundle/nifi-hive-processors/src/main/java/org/apache/nifi/dbcp/hive/HiveConnectionPool.java
index 959c31b..c7bb424 100644
--- 
a/nifi-nar-bundles/nifi-hive-bundle/nifi-hive-processors/src/main/java/org/apache/nifi/dbcp/hive/HiveConnectionPool.java
+++ 
b/nifi-nar-bundles/nifi-hive-bundle/nifi-hive-processors/src/main/java/org/apache/nifi/dbcp/hive/HiveConnectionPool.java
@@ -44,13 +44,13 @@ import org.apache.nifi.processor.exception.ProcessException;
 import org.apache.nifi.processor.util.StandardValidators;
 import org.apache.nifi.reporting.InitializationException;
 import org.apache.nifi.security.krb.KerberosKeytabUser;
+import org.apache.nifi.security.krb.KerberosLoginException;
 import org.apache.nifi.security.krb.KerberosPasswordUser;
 import org.apache.nifi.security.krb.KerberosUser;
 import org.apache.nifi.util.hive.AuthenticationFailedException;
 import org.apache.nifi.util.hive.HiveConfigurator;
 import org.apache.nifi.util.hive.ValidationResources;
 
-import javax.security.auth.login.LoginException;
 import java.io.File;
 import java.io.IOException;
 import java.lang.reflect.UndeclaredThrowableException;
@@ -401,7 +401,7 @@ public class HiveConnectionPool extends 
AbstractControllerService implements Hiv
                     try {
                         getLogger().debug("checking TGT on kerberosUser [{}]", 
new Object[]{kerberosUser});
                         kerberosUser.checkTGTAndRelogin();
-                    } catch (LoginException e) {
+                    } catch (final KerberosLoginException e) {
                         throw new ProcessException("Unable to relogin with 
kerberos credentials for " + kerberosUser.getPrincipal(), e);
                     }
                 } else {
diff --git 
a/nifi-nar-bundles/nifi-hive-bundle/nifi-hive-processors/src/main/java/org/apache/nifi/processors/hive/PutHiveStreaming.java
 
b/nifi-nar-bundles/nifi-hive-bundle/nifi-hive-processors/src/main/java/org/apache/nifi/processors/hive/PutHiveStreaming.java
index 9173486..f1a3679 100644
--- 
a/nifi-nar-bundles/nifi-hive-bundle/nifi-hive-processors/src/main/java/org/apache/nifi/processors/hive/PutHiveStreaming.java
+++ 
b/nifi-nar-bundles/nifi-hive-bundle/nifi-hive-processors/src/main/java/org/apache/nifi/processors/hive/PutHiveStreaming.java
@@ -65,6 +65,7 @@ import 
org.apache.nifi.processor.util.pattern.ExceptionHandler;
 import org.apache.nifi.processor.util.pattern.RollbackOnFailure;
 import org.apache.nifi.processor.util.pattern.RoutingResult;
 import org.apache.nifi.security.krb.KerberosKeytabUser;
+import org.apache.nifi.security.krb.KerberosLoginException;
 import org.apache.nifi.security.krb.KerberosPasswordUser;
 import org.apache.nifi.security.krb.KerberosUser;
 import org.apache.nifi.util.hive.AuthenticationFailedException;
@@ -75,7 +76,6 @@ import org.apache.nifi.util.hive.HiveWriter;
 import org.apache.nifi.util.hive.ValidationResources;
 import org.xerial.snappy.Snappy;
 
-import javax.security.auth.login.LoginException;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
@@ -1173,7 +1173,7 @@ public class PutHiveStreaming extends 
AbstractSessionFactoryProcessor {
             try {
                 getLogger().debug("checking TGT on kerberosUser [{}]", new 
Object[] {kerberosUser});
                 kerberosUser.checkTGTAndRelogin();
-            } catch (LoginException e) {
+            } catch (final KerberosLoginException e) {
                 throw new ProcessException("Unable to relogin with kerberos 
credentials for " + kerberosUser.getPrincipal(), e);
             }
         } else {
diff --git 
a/nifi-nar-bundles/nifi-hive-bundle/nifi-hive3-processors/src/main/java/org/apache/nifi/dbcp/hive/Hive3ConnectionPool.java
 
b/nifi-nar-bundles/nifi-hive-bundle/nifi-hive3-processors/src/main/java/org/apache/nifi/dbcp/hive/Hive3ConnectionPool.java
index ef03c76..75ad406 100644
--- 
a/nifi-nar-bundles/nifi-hive-bundle/nifi-hive3-processors/src/main/java/org/apache/nifi/dbcp/hive/Hive3ConnectionPool.java
+++ 
b/nifi-nar-bundles/nifi-hive-bundle/nifi-hive3-processors/src/main/java/org/apache/nifi/dbcp/hive/Hive3ConnectionPool.java
@@ -45,13 +45,13 @@ import org.apache.nifi.processor.exception.ProcessException;
 import org.apache.nifi.processor.util.StandardValidators;
 import org.apache.nifi.reporting.InitializationException;
 import org.apache.nifi.security.krb.KerberosKeytabUser;
+import org.apache.nifi.security.krb.KerberosLoginException;
 import org.apache.nifi.security.krb.KerberosPasswordUser;
 import org.apache.nifi.security.krb.KerberosUser;
 import org.apache.nifi.util.hive.AuthenticationFailedException;
 import org.apache.nifi.util.hive.HiveConfigurator;
 import org.apache.nifi.util.hive.ValidationResources;
 
-import javax.security.auth.login.LoginException;
 import java.io.File;
 import java.io.IOException;
 import java.lang.reflect.UndeclaredThrowableException;
@@ -502,7 +502,7 @@ public class Hive3ConnectionPool extends 
AbstractControllerService implements Hi
                     try {
                         getLogger().debug("checking TGT on kerberosUser " + 
kerberosUser);
                         kerberosUser.checkTGTAndRelogin();
-                    } catch (LoginException e) {
+                    } catch (final KerberosLoginException e) {
                         throw new ProcessException("Unable to relogin with 
kerberos credentials for " + kerberosUser.getPrincipal(), e);
                     }
                 } else {
diff --git 
a/nifi-nar-bundles/nifi-hive-bundle/nifi-hive3-processors/src/main/java/org/apache/nifi/processors/hive/PutHive3Streaming.java
 
b/nifi-nar-bundles/nifi-hive-bundle/nifi-hive3-processors/src/main/java/org/apache/nifi/processors/hive/PutHive3Streaming.java
index b7a3573..ad5555e 100644
--- 
a/nifi-nar-bundles/nifi-hive-bundle/nifi-hive3-processors/src/main/java/org/apache/nifi/processors/hive/PutHive3Streaming.java
+++ 
b/nifi-nar-bundles/nifi-hive-bundle/nifi-hive3-processors/src/main/java/org/apache/nifi/processors/hive/PutHive3Streaming.java
@@ -59,6 +59,7 @@ import 
org.apache.nifi.processor.util.pattern.DiscontinuedException;
 import org.apache.nifi.processor.util.pattern.RollbackOnFailure;
 import 
org.apache.nifi.processors.hadoop.exception.RecordReaderFactoryException;
 import org.apache.nifi.security.krb.KerberosKeytabUser;
+import org.apache.nifi.security.krb.KerberosLoginException;
 import org.apache.nifi.security.krb.KerberosPasswordUser;
 import org.apache.nifi.security.krb.KerberosUser;
 import org.apache.nifi.serialization.RecordReader;
@@ -69,7 +70,6 @@ import org.apache.nifi.util.hive.HiveConfigurator;
 import org.apache.nifi.util.hive.HiveOptions;
 import org.apache.nifi.util.hive.ValidationResources;
 
-import javax.security.auth.login.LoginException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.security.PrivilegedAction;
@@ -684,7 +684,7 @@ public class PutHive3Streaming extends AbstractProcessor {
             try {
                 getLogger().debug("checking TGT on kerberosUser [{}]", new 
Object[]{kerberosUser});
                 kerberosUser.checkTGTAndRelogin();
-            } catch (LoginException e) {
+            } catch (final KerberosLoginException e) {
                 throw new ProcessException("Unable to relogin with kerberos 
credentials for " + kerberosUser.getPrincipal(), e);
             }
         } else {
diff --git 
a/nifi-nar-bundles/nifi-hive-bundle/nifi-hive_1_1-processors/src/main/java/org/apache/nifi/dbcp/hive/Hive_1_1ConnectionPool.java
 
b/nifi-nar-bundles/nifi-hive-bundle/nifi-hive_1_1-processors/src/main/java/org/apache/nifi/dbcp/hive/Hive_1_1ConnectionPool.java
index ebd0942..26116aa 100644
--- 
a/nifi-nar-bundles/nifi-hive-bundle/nifi-hive_1_1-processors/src/main/java/org/apache/nifi/dbcp/hive/Hive_1_1ConnectionPool.java
+++ 
b/nifi-nar-bundles/nifi-hive-bundle/nifi-hive_1_1-processors/src/main/java/org/apache/nifi/dbcp/hive/Hive_1_1ConnectionPool.java
@@ -44,13 +44,13 @@ import org.apache.nifi.processor.exception.ProcessException;
 import org.apache.nifi.processor.util.StandardValidators;
 import org.apache.nifi.reporting.InitializationException;
 import org.apache.nifi.security.krb.KerberosKeytabUser;
+import org.apache.nifi.security.krb.KerberosLoginException;
 import org.apache.nifi.security.krb.KerberosPasswordUser;
 import org.apache.nifi.security.krb.KerberosUser;
 import org.apache.nifi.util.hive.AuthenticationFailedException;
 import org.apache.nifi.util.hive.HiveConfigurator;
 import org.apache.nifi.util.hive.ValidationResources;
 
-import javax.security.auth.login.LoginException;
 import java.io.IOException;
 import java.lang.reflect.UndeclaredThrowableException;
 import java.security.PrivilegedExceptionAction;
@@ -403,7 +403,7 @@ public class Hive_1_1ConnectionPool extends 
AbstractControllerService implements
                     try {
                         getLogger().debug("checking TGT on kerberosUser " + 
kerberosUser);
                         kerberosUser.checkTGTAndRelogin();
-                    } catch (LoginException e) {
+                    } catch (final KerberosLoginException e) {
                         throw new ProcessException("Unable to relogin with 
kerberos credentials for " + kerberosUser.getPrincipal(), e);
                     }
                 } else {
diff --git 
a/nifi-nar-bundles/nifi-kudu-bundle/nifi-kudu-processors/src/main/java/org/apache/nifi/processors/kudu/AbstractKuduProcessor.java
 
b/nifi-nar-bundles/nifi-kudu-bundle/nifi-kudu-processors/src/main/java/org/apache/nifi/processors/kudu/AbstractKuduProcessor.java
index 8724254..4131d2f 100644
--- 
a/nifi-nar-bundles/nifi-kudu-bundle/nifi-kudu-processors/src/main/java/org/apache/nifi/processors/kudu/AbstractKuduProcessor.java
+++ 
b/nifi-nar-bundles/nifi-kudu-bundle/nifi-kudu-processors/src/main/java/org/apache/nifi/processors/kudu/AbstractKuduProcessor.java
@@ -263,7 +263,7 @@ public abstract class AbstractKuduProcessor extends 
AbstractProcessor {
     protected KerberosUser createKerberosKeytabUser(String principal, String 
keytab, ProcessContext context) {
         return new KerberosKeytabUser(principal, keytab) {
             @Override
-            public synchronized void login() throws LoginException {
+            public synchronized void login() {
                 if (!isLoggedIn()) {
                     super.login();
 
@@ -276,7 +276,7 @@ public abstract class AbstractKuduProcessor extends 
AbstractProcessor {
     protected KerberosUser createKerberosPasswordUser(String principal, String 
password, ProcessContext context) {
         return new KerberosPasswordUser(principal, password) {
             @Override
-            public synchronized void login() throws LoginException {
+            public synchronized void login() {
                 if (!isLoggedIn()) {
                     super.login();
 
diff --git 
a/nifi-nar-bundles/nifi-solr-bundle/nifi-solr-processors/src/main/java/org/apache/nifi/processors/solr/SolrProcessor.java
 
b/nifi-nar-bundles/nifi-solr-bundle/nifi-solr-processors/src/main/java/org/apache/nifi/processors/solr/SolrProcessor.java
index 332bf12..e9d440b 100644
--- 
a/nifi-nar-bundles/nifi-solr-bundle/nifi-solr-processors/src/main/java/org/apache/nifi/processors/solr/SolrProcessor.java
+++ 
b/nifi-nar-bundles/nifi-solr-bundle/nifi-solr-processors/src/main/java/org/apache/nifi/processors/solr/SolrProcessor.java
@@ -29,13 +29,13 @@ import org.apache.nifi.processor.ProcessContext;
 import org.apache.nifi.processor.ProcessSession;
 import org.apache.nifi.processor.exception.ProcessException;
 import org.apache.nifi.security.krb.KerberosAction;
+import org.apache.nifi.security.krb.KerberosLoginException;
 import org.apache.nifi.security.krb.KerberosPasswordUser;
 import org.apache.nifi.security.krb.KerberosUser;
 import org.apache.nifi.security.krb.KerberosKeytabUser;
 import org.apache.nifi.ssl.SSLContextService;
 import org.apache.solr.client.solrj.SolrClient;
 
-import javax.security.auth.login.LoginException;
 import java.io.IOException;
 import java.security.PrivilegedExceptionAction;
 import java.util.ArrayList;
@@ -113,7 +113,7 @@ public abstract class SolrProcessor extends 
AbstractProcessor {
             try {
                 kerberosUser.logout();
                 kerberosUser = null;
-            } catch (LoginException e) {
+            } catch (final KerberosLoginException e) {
                 getLogger().debug("Error logging out keytab user", e);
             }
         }
diff --git 
a/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/src/main/java/org/apache/nifi/dbcp/DBCPConnectionPool.java
 
b/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/src/main/java/org/apache/nifi/dbcp/DBCPConnectionPool.java
index b43f691..945412d 100644
--- 
a/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/src/main/java/org/apache/nifi/dbcp/DBCPConnectionPool.java
+++ 
b/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/src/main/java/org/apache/nifi/dbcp/DBCPConnectionPool.java
@@ -42,6 +42,7 @@ import org.apache.nifi.processor.util.StandardValidators;
 import org.apache.nifi.reporting.InitializationException;
 import org.apache.nifi.security.krb.KerberosAction;
 import org.apache.nifi.security.krb.KerberosKeytabUser;
+import org.apache.nifi.security.krb.KerberosLoginException;
 import org.apache.nifi.security.krb.KerberosPasswordUser;
 import org.apache.nifi.security.krb.KerberosUser;
 
@@ -413,7 +414,7 @@ public class DBCPConnectionPool extends 
AbstractControllerService implements DBC
         if (kerberosUser != null) {
             try {
                 kerberosUser.login();
-            } catch (LoginException e) {
+            } catch (KerberosLoginException e) {
                 throw new InitializationException("Unable to authenticate 
Kerberos principal", e);
             }
         }
@@ -530,7 +531,7 @@ public class DBCPConnectionPool extends 
AbstractControllerService implements DBC
                 try {
                     getLogger().info("Error getting connection, performing 
Kerberos re-login");
                     kerberosUser.login();
-                } catch (LoginException le) {
+                } catch (KerberosLoginException le) {
                     throw new ProcessException("Unable to authenticate 
Kerberos principal", le);
                 }
             }
diff --git 
a/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/src/test/groovy/org/apache/nifi/dbcp/GroovyDBCPServiceTest.groovy
 
b/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/src/test/groovy/org/apache/nifi/dbcp/GroovyDBCPServiceTest.groovy
index cb267db..4d27530 100644
--- 
a/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/src/test/groovy/org/apache/nifi/dbcp/GroovyDBCPServiceTest.groovy
+++ 
b/nifi-nar-bundles/nifi-standard-services/nifi-dbcp-service-bundle/nifi-dbcp-service/src/test/groovy/org/apache/nifi/dbcp/GroovyDBCPServiceTest.groovy
@@ -19,13 +19,13 @@ package org.apache.nifi.dbcp
 import org.apache.commons.dbcp2.BasicDataSource
 import org.apache.nifi.reporting.InitializationException
 import org.apache.nifi.security.krb.KerberosKeytabUser
+import org.apache.nifi.security.krb.KerberosLoginException
 import org.apache.nifi.util.TestRunner
 import org.apache.nifi.util.TestRunners
 import org.junit.Assert
 import org.junit.BeforeClass
 import org.junit.Test
 
-import javax.security.auth.login.LoginException
 import java.sql.Connection
 import java.sql.SQLException
 
@@ -76,7 +76,7 @@ class GroovyDBCPServiceTest {
         }
     }
 
-    @Test(expected = LoginException)
+    @Test(expected = KerberosLoginException)
     void testDatasourceCloseSuccessWithKerberosUserLogoutException() {
         final DBCPConnectionPool dbcpConnectionPoolService = new 
DBCPConnectionPool()
 
@@ -84,8 +84,8 @@ class GroovyDBCPServiceTest {
         dbcpConnectionPoolService.dataSource = basicDataSource
         def kerberosKeytabUser = new KerberosKeytabUser("[email protected]", 
"fake.keytab") {
             @Override
-            void logout() throws LoginException {
-                throw new LoginException("fake logout exception")
+            void logout() {
+                throw new KerberosLoginException("fake logout exception")
             }
         }
         dbcpConnectionPoolService.kerberosUser = kerberosKeytabUser
@@ -104,7 +104,7 @@ class GroovyDBCPServiceTest {
         dbcpConnectionPoolService.dataSource = basicDataSource
         def kerberosKeytabUser = new KerberosKeytabUser("[email protected]", 
"fake.keytab") {
             @Override
-            void logout() throws LoginException {
+            void logout() {
             }
         }
         dbcpConnectionPoolService.kerberosUser = kerberosKeytabUser
@@ -122,8 +122,8 @@ class GroovyDBCPServiceTest {
         dbcpConnectionPoolService.dataSource = basicDataSource
         def kerberosKeytabUser = new KerberosKeytabUser("[email protected]", 
"fake.keytab") {
             @Override
-            void logout() throws LoginException {
-                throw new LoginException("fake logout exception")
+            void logout() {
+                throw new KerberosLoginException("fake logout exception")
             }
         }
         dbcpConnectionPoolService.kerberosUser = kerberosKeytabUser
diff --git 
a/nifi-nar-bundles/nifi-standard-services/nifi-hadoop-dbcp-service-bundle/nifi-hadoop-dbcp-service/src/main/java/org/apache/nifi/dbcp/HadoopDBCPConnectionPool.java
 
b/nifi-nar-bundles/nifi-standard-services/nifi-hadoop-dbcp-service-bundle/nifi-hadoop-dbcp-service/src/main/java/org/apache/nifi/dbcp/HadoopDBCPConnectionPool.java
index 7bdd631..614d5f8 100644
--- 
a/nifi-nar-bundles/nifi-standard-services/nifi-hadoop-dbcp-service-bundle/nifi-hadoop-dbcp-service/src/main/java/org/apache/nifi/dbcp/HadoopDBCPConnectionPool.java
+++ 
b/nifi-nar-bundles/nifi-standard-services/nifi-hadoop-dbcp-service-bundle/nifi-hadoop-dbcp-service/src/main/java/org/apache/nifi/dbcp/HadoopDBCPConnectionPool.java
@@ -44,6 +44,7 @@ import org.apache.nifi.processor.exception.ProcessException;
 import org.apache.nifi.processor.util.StandardValidators;
 import org.apache.nifi.reporting.InitializationException;
 import org.apache.nifi.security.krb.KerberosKeytabUser;
+import org.apache.nifi.security.krb.KerberosLoginException;
 import org.apache.nifi.security.krb.KerberosPasswordUser;
 import org.apache.nifi.security.krb.KerberosUser;
 
@@ -529,7 +530,7 @@ public class HadoopDBCPConnectionPool extends 
AbstractControllerService implemen
      * no exception while closing open connections
      */
     @OnDisabled
-    public void shutdown() throws SQLException, LoginException {
+    public void shutdown() throws SQLException {
         try {
             if (kerberosUser != null) {
                 kerberosUser.logout();
@@ -562,7 +563,7 @@ public class HadoopDBCPConnectionPool extends 
AbstractControllerService implemen
                     try {
                         getLogger().debug("checking TGT on kerberosUser " + 
kerberosUser);
                         kerberosUser.checkTGTAndRelogin();
-                    } catch (LoginException e) {
+                    } catch (final KerberosLoginException e) {
                         throw new ProcessException("Unable to relogin with 
kerberos credentials for " + kerberosUser.getPrincipal(), e);
                     }
                 } else {
diff --git 
a/nifi-nar-bundles/nifi-standard-services/nifi-hbase_1_1_2-client-service-bundle/nifi-hbase_1_1_2-client-service/pom.xml
 
b/nifi-nar-bundles/nifi-standard-services/nifi-hbase_1_1_2-client-service-bundle/nifi-hbase_1_1_2-client-service/pom.xml
index 1374977..af692dc 100644
--- 
a/nifi-nar-bundles/nifi-standard-services/nifi-hbase_1_1_2-client-service-bundle/nifi-hbase_1_1_2-client-service/pom.xml
+++ 
b/nifi-nar-bundles/nifi-standard-services/nifi-hbase_1_1_2-client-service-bundle/nifi-hbase_1_1_2-client-service/pom.xml
@@ -62,7 +62,6 @@
         <dependency>
             <groupId>org.apache.nifi</groupId>
             <artifactId>nifi-distributed-cache-client-service-api</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.nifi</groupId>
@@ -72,7 +71,10 @@
         <dependency>
             <groupId>org.apache.nifi</groupId>
             <artifactId>nifi-kerberos-credentials-service-api</artifactId>
-            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-kerberos-user-service-api</artifactId>
         </dependency>
 
         <dependency>
diff --git 
a/nifi-nar-bundles/nifi-standard-services/nifi-hbase_1_1_2-client-service-bundle/nifi-hbase_1_1_2-client-service/src/main/java/org/apache/nifi/hbase/HBase_1_1_2_ClientService.java
 
b/nifi-nar-bundles/nifi-standard-services/nifi-hbase_1_1_2-client-service-bundle/nifi-hbase_1_1_2-client-service/src/main/java/org/apache/nifi/hbase/HBase_1_1_2_ClientService.java
index d02c2b5..bd029c8 100644
--- 
a/nifi-nar-bundles/nifi-standard-services/nifi-hbase_1_1_2-client-service-bundle/nifi-hbase_1_1_2-client-service/src/main/java/org/apache/nifi/hbase/HBase_1_1_2_ClientService.java
+++ 
b/nifi-nar-bundles/nifi-standard-services/nifi-hbase_1_1_2-client-service-bundle/nifi-hbase_1_1_2-client-service/src/main/java/org/apache/nifi/hbase/HBase_1_1_2_ClientService.java
@@ -63,6 +63,7 @@ import org.apache.nifi.hbase.scan.Column;
 import org.apache.nifi.hbase.scan.ResultCell;
 import org.apache.nifi.hbase.scan.ResultHandler;
 import org.apache.nifi.kerberos.KerberosCredentialsService;
+import org.apache.nifi.kerberos.KerberosUserService;
 import org.apache.nifi.processor.util.StandardValidators;
 import org.apache.nifi.reporting.InitializationException;
 import org.apache.nifi.security.krb.KerberosKeytabUser;
@@ -106,6 +107,14 @@ public class HBase_1_1_2_ClientService extends 
AbstractControllerService impleme
         .required(false)
         .build();
 
+    static final PropertyDescriptor KERBEROS_USER_SERVICE = new 
PropertyDescriptor.Builder()
+            .name("kerberos-user-service")
+            .displayName("Kerberos User Service")
+            .description("Specifies the Kerberos User Controller Service that 
should be used for authenticating with Kerberos")
+            .identifiesControllerService(KerberosUserService.class)
+            .required(false)
+            .build();
+
     static final PropertyDescriptor HADOOP_CONF_FILES = new 
PropertyDescriptor.Builder()
         .name("Hadoop Configuration Files")
         .description("Comma-separated list of Hadoop Configuration files," +
@@ -184,6 +193,7 @@ public class HBase_1_1_2_ClientService extends 
AbstractControllerService impleme
 
         List<PropertyDescriptor> props = new ArrayList<>();
         props.add(HADOOP_CONF_FILES);
+        props.add(KERBEROS_USER_SERVICE);
         props.add(KERBEROS_CREDENTIALS_SERVICE);
         props.add(kerberosProperties.getKerberosPrincipal());
         props.add(kerberosProperties.getKerberosKeytab());
@@ -232,6 +242,7 @@ public class HBase_1_1_2_ClientService extends 
AbstractControllerService impleme
         final String explicitKeytab = 
validationContext.getProperty(kerberosProperties.getKerberosKeytab()).evaluateAttributeExpressions().getValue();
         final String explicitPassword = 
validationContext.getProperty(kerberosProperties.getKerberosPassword()).getValue();
         final KerberosCredentialsService credentialsService = 
validationContext.getProperty(KERBEROS_CREDENTIALS_SERVICE).asControllerService(KerberosCredentialsService.class);
+        final KerberosUserService kerberosUserService = 
validationContext.getProperty(KERBEROS_USER_SERVICE).asControllerService(KerberosUserService.class);
 
         final String resolvedPrincipal;
         final String resolvedKeytab;
@@ -267,9 +278,15 @@ public class HBase_1_1_2_ClientService extends 
AbstractControllerService impleme
             }
 
             final Configuration hbaseConfig = resources.getConfiguration();
-
-            
problems.addAll(KerberosProperties.validatePrincipalWithKeytabOrPassword(getClass().getSimpleName(),
 hbaseConfig,
-                    resolvedPrincipal, resolvedKeytab, explicitPassword, 
getLogger()));
+            if (kerberosUserService == null) {
+                
problems.addAll(KerberosProperties.validatePrincipalWithKeytabOrPassword(getClass().getSimpleName(),
 hbaseConfig,
+                        resolvedPrincipal, resolvedKeytab, explicitPassword, 
getLogger()));
+            } else {
+                final boolean securityEnabled = 
SecurityUtil.isSecurityEnabled(hbaseConfig);
+                if (!securityEnabled) {
+                    getLogger().warn("Hadoop Configuration does not have 
security enabled, KerberosUserService will be ignored");
+                }
+            }
         }
 
         if (credentialsService != null && (explicitPrincipal != null || 
explicitKeytab != null || explicitPassword != null)) {
@@ -280,6 +297,22 @@ public class HBase_1_1_2_ClientService extends 
AbstractControllerService impleme
                 .build());
         }
 
+        if (kerberosUserService != null && (explicitPrincipal != null || 
explicitKeytab != null || explicitPassword != null)) {
+            problems.add(new ValidationResult.Builder()
+                    .subject("Kerberos User")
+                    .valid(false)
+                    .explanation("Cannot specify a Kerberos User Service while 
also specifying a Kerberos Principal, Kerberos Keytab, or Kerberos Password")
+                    .build());
+        }
+
+        if (kerberosUserService != null && credentialsService != null) {
+            problems.add(new ValidationResult.Builder()
+                    .subject("Kerberos User")
+                    .valid(false)
+                    .explanation("Cannot specify a Kerberos User Service while 
also specifying a Kerberos Credentials Service")
+                    .build());
+        }
+
         if (!isAllowExplicitKeytab() && explicitKeytab != null) {
             problems.add(new ValidationResult.Builder()
                 .subject("Kerberos Credentials")
@@ -359,43 +392,45 @@ public class HBase_1_1_2_ClientService extends 
AbstractControllerService impleme
         }
 
         if (SecurityUtil.isSecurityEnabled(hbaseConfig)) {
-            String principal = 
context.getProperty(kerberosProperties.getKerberosPrincipal()).evaluateAttributeExpressions().getValue();
-            String keyTab = 
context.getProperty(kerberosProperties.getKerberosKeytab()).evaluateAttributeExpressions().getValue();
-            String password = 
context.getProperty(kerberosProperties.getKerberosPassword()).getValue();
-
-            // If the Kerberos Credentials Service is specified, we need to 
use its configuration, not the explicit properties for principal/keytab.
-            // The customValidate method ensures that only one can be set, so 
we know that the principal & keytab above are null.
-            final KerberosCredentialsService credentialsService = 
context.getProperty(KERBEROS_CREDENTIALS_SERVICE).asControllerService(KerberosCredentialsService.class);
-            if (credentialsService != null) {
-                principal = credentialsService.getPrincipal();
-                keyTab = credentialsService.getKeytab();
-            }
+            getLogger().debug("HBase Security Enabled, creating KerberosUser");
+            final KerberosUser kerberosUser = createKerberosUser(context);
+            ugi = SecurityUtil.getUgiForKerberosUser(hbaseConfig, 
kerberosUser);
+            kerberosUserReference.set(kerberosUser);
+            getLogger().info("Successfully logged in as principal {}", 
kerberosUser.getPrincipal());
+            return getUgi().doAs((PrivilegedExceptionAction<Connection>)() ->  
ConnectionFactory.createConnection(hbaseConfig));
+        } else {
+            getLogger().debug("Simple Authentication");
+            return ConnectionFactory.createConnection(hbaseConfig);
+        }
+    }
 
-            if (keyTab != null) {
-                kerberosUserReference.set(new KerberosKeytabUser(principal, 
keyTab));
-                getLogger().info("HBase Security Enabled, logging in as 
principal {} with keytab {}", new Object[] {principal, keyTab});
-            } else if (password != null) {
-                kerberosUserReference.set(new KerberosPasswordUser(principal, 
password));
-                getLogger().info("HBase Security Enabled, logging in as 
principal {} with password", new Object[] {principal});
-            } else {
-                throw new IOException("Unable to authenticate with Kerberos, 
no keytab or password was provided");
-            }
+    protected KerberosUser createKerberosUser(final ConfigurationContext 
context) {
+        // Check Kerberos User Service first, if present then get the 
KerberosUser from the service
+        // The customValidate method ensures that KerberosUserService can't be 
set at the same time as the credentials service or explicit properties
+        final KerberosUserService kerberosUserService = 
context.getProperty(KERBEROS_USER_SERVICE).asControllerService(KerberosUserService.class);
+        if (kerberosUserService != null) {
+            return kerberosUserService.createKerberosUser();
+        }
 
-            ugi = SecurityUtil.getUgiForKerberosUser(hbaseConfig, 
kerberosUserReference.get());
-            getLogger().info("Successfully logged in as principal " + 
principal);
+        String principal = 
context.getProperty(kerberosProperties.getKerberosPrincipal()).evaluateAttributeExpressions().getValue();
+        String keyTab = 
context.getProperty(kerberosProperties.getKerberosKeytab()).evaluateAttributeExpressions().getValue();
+        String password = 
context.getProperty(kerberosProperties.getKerberosPassword()).getValue();
 
-            return getUgi().doAs(new PrivilegedExceptionAction<Connection>() {
-                @Override
-                public Connection run() throws Exception {
-                    return ConnectionFactory.createConnection(hbaseConfig);
-                }
-            });
+        // If the Kerberos Credentials Service is specified, we need to use 
its configuration, not the explicit properties for principal/keytab.
+        // The customValidate method ensures that only one can be set, so we 
know that the principal & keytab above are null.
+        final KerberosCredentialsService credentialsService = 
context.getProperty(KERBEROS_CREDENTIALS_SERVICE).asControllerService(KerberosCredentialsService.class);
+        if (credentialsService != null) {
+            principal = credentialsService.getPrincipal();
+            keyTab = credentialsService.getKeytab();
+        }
 
+        if (keyTab != null) {
+            return new KerberosKeytabUser(principal, keyTab);
+        } else if (password != null) {
+            return new KerberosPasswordUser(principal, password);
         } else {
-            getLogger().info("Simple Authentication");
-            return ConnectionFactory.createConnection(hbaseConfig);
+            throw new IllegalStateException("Unable to authenticate with 
Kerberos, no keytab or password was provided");
         }
-
     }
 
     protected Configuration getConfigurationFromFiles(final String 
configFiles) {
@@ -417,6 +452,18 @@ public class HBase_1_1_2_ClientService extends 
AbstractControllerService impleme
                 getLogger().warn("Failed to close connection to HBase due to 
{}", new Object[]{ioe});
             }
         }
+
+        final KerberosUser kerberosUser = kerberosUserReference.get();
+        if (kerberosUser != null) {
+            try {
+                kerberosUser.logout();
+            } catch (final Exception e) {
+                getLogger().warn("Error logging out KerberosUser: {}", 
e.getMessage(), e);
+            } finally {
+                ugi = null;
+                kerberosUserReference.set(null);
+            }
+        }
     }
 
     protected List<Put> buildPuts(byte[] rowKey, List<PutColumn> columns) {
@@ -890,6 +937,8 @@ public class HBase_1_1_2_ClientService extends 
AbstractControllerService impleme
     }
 
     UserGroupInformation getUgi() {
+        getLogger().trace("getting UGI instance");
+        // if there is a KerberosUser associated with UGI, call 
checkTGTAndRelogin to ensure UGI's underlying Subject has a valid ticket
         SecurityUtil.checkTGTAndRelogin(getLogger(), 
kerberosUserReference.get());
         return ugi;
     }
diff --git 
a/nifi-nar-bundles/nifi-standard-services/nifi-hbase_1_1_2-client-service-bundle/nifi-hbase_1_1_2-client-service/src/test/java/org/apache/nifi/hbase/TestHBase_1_1_2_ClientService.java
 
b/nifi-nar-bundles/nifi-standard-services/nifi-hbase_1_1_2-client-service-bundle/nifi-hbase_1_1_2-client-service/src/test/java/org/apache/nifi/hbase/TestHBase_1_1_2_ClientService.java
index 56b259c..4467538 100644
--- 
a/nifi-nar-bundles/nifi-standard-services/nifi-hbase_1_1_2-client-service-bundle/nifi-hbase_1_1_2-client-service/src/test/java/org/apache/nifi/hbase/TestHBase_1_1_2_ClientService.java
+++ 
b/nifi-nar-bundles/nifi-standard-services/nifi-hbase_1_1_2-client-service-bundle/nifi-hbase_1_1_2-client-service/src/test/java/org/apache/nifi/hbase/TestHBase_1_1_2_ClientService.java
@@ -26,6 +26,8 @@ import org.apache.nifi.hbase.put.PutFlowFile;
 import org.apache.nifi.hbase.scan.Column;
 import org.apache.nifi.hbase.scan.ResultCell;
 import org.apache.nifi.hbase.scan.ResultHandler;
+import org.apache.nifi.kerberos.KerberosCredentialsService;
+import org.apache.nifi.kerberos.KerberosUserService;
 import org.apache.nifi.reporting.InitializationException;
 import org.apache.nifi.util.TestRunner;
 import org.apache.nifi.util.TestRunners;
@@ -49,6 +51,7 @@ import java.util.NavigableMap;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -178,6 +181,81 @@ public class TestHBase_1_1_2_ClientService {
         runner.setProperty(service, 
kerberosPropsWithoutFile.getKerberosKeytab(), "src/test/resources/fake.keytab");
         runner.setProperty(service, 
kerberosPropsWithoutFile.getKerberosPrincipal(), "test@REALM");
         runner.assertNotValid(service);
+
+        // Kerberos - add valid options with password
+        service = new MockHBaseClientService(table, COL_FAM, 
kerberosPropsWithFile, true);
+        runner.addControllerService("hbaseClientService", service);
+        runner.setProperty(service, 
HBase_1_1_2_ClientService.HADOOP_CONF_FILES,
+                "src/test/resources/hbase-site.xml, 
src/test/resources/core-site-security.xml");
+        runner.setProperty(service, 
kerberosPropsWithFile.getKerberosPassword(), "password");
+        runner.setProperty(service, 
kerberosPropsWithFile.getKerberosPrincipal(), "test@REALM");
+        runner.assertValid(service);
+
+        // Kerberos - keytab and password at same time should be invalid
+        runner.setProperty(service, kerberosPropsWithFile.getKerberosKeytab(), 
"src/test/resources/fake.keytab");
+        runner.assertNotValid(service);
+
+        runner.removeProperty(service, 
kerberosPropsWithFile.getKerberosKeytab());
+        runner.assertValid(service);
+
+        // Kerberos - credentials service not valid when other kerberos 
properties set
+        final KerberosCredentialsService credentialsService = 
enabledKerberosCredentialsService(runner);
+        runner.setProperty(service, 
HBase_1_1_2_ClientService.KERBEROS_CREDENTIALS_SERVICE, 
credentialsService.getIdentifier());
+        runner.assertNotValid(service);
+
+        runner.removeProperty(service, 
kerberosPropsWithFile.getKerberosPassword());
+        runner.assertNotValid(service);
+
+        runner.removeProperty(service, 
kerberosPropsWithFile.getKerberosPrincipal());
+        runner.assertValid(service);
+
+        runner.setProperty(service, kerberosPropsWithFile.getKerberosKeytab(), 
"src/test/resources/fake.keytab");
+        runner.assertNotValid(service);
+
+        runner.removeProperty(service, 
kerberosPropsWithFile.getKerberosKeytab());
+        runner.assertValid(service);
+
+        // Kerberos - user service with credentials service is invalid
+        final KerberosUserService userService = 
enableKerberosUserService(runner);
+        runner.setProperty(service, 
HBase_1_1_2_ClientService.KERBEROS_USER_SERVICE, userService.getIdentifier());
+        runner.assertNotValid(service);
+
+        runner.removeProperty(service, 
HBase_1_1_2_ClientService.KERBEROS_CREDENTIALS_SERVICE);
+        runner.assertValid(service);
+
+        // Kerberos - user service with other kerberos properties is invalid
+        runner.setProperty(service, 
kerberosPropsWithFile.getKerberosPassword(), "password");
+        runner.setProperty(service, 
kerberosPropsWithFile.getKerberosPrincipal(), "test@REALM");
+        runner.assertNotValid(service);
+
+        runner.removeProperty(service, 
kerberosPropsWithFile.getKerberosPassword());
+        runner.setProperty(service, kerberosPropsWithFile.getKerberosKeytab(), 
"src/test/resources/fake.keytab");
+        runner.assertNotValid(service);
+
+        runner.removeProperty(service, 
kerberosPropsWithFile.getKerberosKeytab());
+        runner.assertNotValid(service);
+
+        runner.removeProperty(service, 
kerberosPropsWithFile.getKerberosPrincipal());
+        runner.assertValid(service);
+    }
+
+    private KerberosUserService enableKerberosUserService(final TestRunner 
runner) throws InitializationException {
+        final KerberosUserService kerberosUserService = 
mock(KerberosUserService.class);
+        when(kerberosUserService.getIdentifier()).thenReturn("userService1");
+        runner.addControllerService(kerberosUserService.getIdentifier(), 
kerberosUserService);
+        runner.enableControllerService(kerberosUserService);
+        return kerberosUserService;
+    }
+
+    private KerberosCredentialsService enabledKerberosCredentialsService(final 
TestRunner runner) throws InitializationException {
+        final KerberosCredentialsService credentialsService = 
mock(KerberosCredentialsService.class);
+        when(credentialsService.getIdentifier()).thenReturn("credsService1");
+        when(credentialsService.getPrincipal()).thenReturn("principal1");
+        when(credentialsService.getKeytab()).thenReturn("keytab1");
+
+        runner.addControllerService(credentialsService.getIdentifier(), 
credentialsService);
+        runner.enableControllerService(credentialsService);
+        return credentialsService;
     }
 
     @Test
diff --git 
a/nifi-nar-bundles/nifi-standard-services/nifi-hbase_2-client-service-bundle/nifi-hbase_2-client-service/pom.xml
 
b/nifi-nar-bundles/nifi-standard-services/nifi-hbase_2-client-service-bundle/nifi-hbase_2-client-service/pom.xml
index 8048593..2649c81 100644
--- 
a/nifi-nar-bundles/nifi-standard-services/nifi-hbase_2-client-service-bundle/nifi-hbase_2-client-service/pom.xml
+++ 
b/nifi-nar-bundles/nifi-standard-services/nifi-hbase_2-client-service-bundle/nifi-hbase_2-client-service/pom.xml
@@ -60,17 +60,18 @@
         <dependency>
             <groupId>org.apache.nifi</groupId>
             <artifactId>nifi-distributed-cache-client-service-api</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.nifi</groupId>
             <artifactId>nifi-record</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.nifi</groupId>
             <artifactId>nifi-kerberos-credentials-service-api</artifactId>
-            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-kerberos-user-service-api</artifactId>
         </dependency>
 
         <dependency>
diff --git 
a/nifi-nar-bundles/nifi-standard-services/nifi-hbase_2-client-service-bundle/nifi-hbase_2-client-service/src/main/java/org/apache/nifi/hbase/HBase_2_ClientService.java
 
b/nifi-nar-bundles/nifi-standard-services/nifi-hbase_2-client-service-bundle/nifi-hbase_2-client-service/src/main/java/org/apache/nifi/hbase/HBase_2_ClientService.java
index 1929de9..d1797d4 100644
--- 
a/nifi-nar-bundles/nifi-standard-services/nifi-hbase_2-client-service-bundle/nifi-hbase_2-client-service/src/main/java/org/apache/nifi/hbase/HBase_2_ClientService.java
+++ 
b/nifi-nar-bundles/nifi-standard-services/nifi-hbase_2-client-service-bundle/nifi-hbase_2-client-service/src/main/java/org/apache/nifi/hbase/HBase_2_ClientService.java
@@ -63,6 +63,7 @@ import org.apache.nifi.hbase.scan.Column;
 import org.apache.nifi.hbase.scan.ResultCell;
 import org.apache.nifi.hbase.scan.ResultHandler;
 import org.apache.nifi.kerberos.KerberosCredentialsService;
+import org.apache.nifi.kerberos.KerberosUserService;
 import org.apache.nifi.processor.util.StandardValidators;
 import org.apache.nifi.reporting.InitializationException;
 import org.apache.nifi.security.krb.KerberosKeytabUser;
@@ -105,6 +106,14 @@ public class HBase_2_ClientService extends 
AbstractControllerService implements
         .required(false)
         .build();
 
+    static final PropertyDescriptor KERBEROS_USER_SERVICE = new 
PropertyDescriptor.Builder()
+            .name("kerberos-user-service")
+            .displayName("Kerberos User Service")
+            .description("Specifies the Kerberos User Controller Service that 
should be used for authenticating with Kerberos")
+            .identifiesControllerService(KerberosUserService.class)
+            .required(false)
+            .build();
+
     static final PropertyDescriptor HADOOP_CONF_FILES = new 
PropertyDescriptor.Builder()
         .name("Hadoop Configuration Files")
         .description("Comma-separated list of Hadoop Configuration files," +
@@ -184,6 +193,7 @@ public class HBase_2_ClientService extends 
AbstractControllerService implements
 
         List<PropertyDescriptor> props = new ArrayList<>();
         props.add(HADOOP_CONF_FILES);
+        props.add(KERBEROS_USER_SERVICE);
         props.add(KERBEROS_CREDENTIALS_SERVICE);
         props.add(kerberosProperties.getKerberosPrincipal());
         props.add(kerberosProperties.getKerberosKeytab());
@@ -232,6 +242,7 @@ public class HBase_2_ClientService extends 
AbstractControllerService implements
         final String explicitKeytab = 
validationContext.getProperty(kerberosProperties.getKerberosKeytab()).evaluateAttributeExpressions().getValue();
         final String explicitPassword = 
validationContext.getProperty(kerberosProperties.getKerberosPassword()).getValue();
         final KerberosCredentialsService credentialsService = 
validationContext.getProperty(KERBEROS_CREDENTIALS_SERVICE).asControllerService(KerberosCredentialsService.class);
+        final KerberosUserService kerberosUserService = 
validationContext.getProperty(KERBEROS_USER_SERVICE).asControllerService(KerberosUserService.class);
 
         final String resolvedPrincipal;
         final String resolvedKeytab;
@@ -267,9 +278,15 @@ public class HBase_2_ClientService extends 
AbstractControllerService implements
             }
 
             final Configuration hbaseConfig = resources.getConfiguration();
-
-            
problems.addAll(KerberosProperties.validatePrincipalWithKeytabOrPassword(getClass().getSimpleName(),
 hbaseConfig,
-                    resolvedPrincipal, resolvedKeytab, explicitPassword, 
getLogger()));
+            if (kerberosUserService == null) {
+                
problems.addAll(KerberosProperties.validatePrincipalWithKeytabOrPassword(getClass().getSimpleName(),
 hbaseConfig,
+                        resolvedPrincipal, resolvedKeytab, explicitPassword, 
getLogger()));
+            } else {
+                final boolean securityEnabled = 
SecurityUtil.isSecurityEnabled(hbaseConfig);
+                if (!securityEnabled) {
+                    getLogger().warn("Hadoop Configuration does not have 
security enabled, KerberosUserService will be ignored");
+                }
+            }
         }
 
         if (credentialsService != null && (explicitPrincipal != null || 
explicitKeytab != null || explicitPassword != null)) {
@@ -280,6 +297,22 @@ public class HBase_2_ClientService extends 
AbstractControllerService implements
                 .build());
         }
 
+        if (kerberosUserService != null && (explicitPrincipal != null || 
explicitKeytab != null || explicitPassword != null)) {
+            problems.add(new ValidationResult.Builder()
+                    .subject("Kerberos User")
+                    .valid(false)
+                    .explanation("Cannot specify a Kerberos User Service while 
also specifying a Kerberos Principal, Kerberos Keytab, or Kerberos Password")
+                    .build());
+        }
+
+        if (kerberosUserService != null && credentialsService != null) {
+            problems.add(new ValidationResult.Builder()
+                    .subject("Kerberos User")
+                    .valid(false)
+                    .explanation("Cannot specify a Kerberos User Service while 
also specifying a Kerberos Credentials Service")
+                    .build());
+        }
+
         if (!isAllowExplicitKeytab() && explicitKeytab != null) {
             problems.add(new ValidationResult.Builder()
                 .subject("Kerberos Credentials")
@@ -359,43 +392,45 @@ public class HBase_2_ClientService extends 
AbstractControllerService implements
         }
 
         if (SecurityUtil.isSecurityEnabled(hbaseConfig)) {
-            String principal = 
context.getProperty(kerberosProperties.getKerberosPrincipal()).evaluateAttributeExpressions().getValue();
-            String keyTab = 
context.getProperty(kerberosProperties.getKerberosKeytab()).evaluateAttributeExpressions().getValue();
-            String password = 
context.getProperty(kerberosProperties.getKerberosPassword()).getValue();
-
-            // If the Kerberos Credentials Service is specified, we need to 
use its configuration, not the explicit properties for principal/keytab.
-            // The customValidate method ensures that only one can be set, so 
we know that the principal & keytab above are null.
-            final KerberosCredentialsService credentialsService = 
context.getProperty(KERBEROS_CREDENTIALS_SERVICE).asControllerService(KerberosCredentialsService.class);
-            if (credentialsService != null) {
-                principal = credentialsService.getPrincipal();
-                keyTab = credentialsService.getKeytab();
-            }
+            getLogger().debug("HBase Security Enabled, creating KerberosUser");
+            final KerberosUser kerberosUser = createKerberosUser(context);
+            ugi = SecurityUtil.getUgiForKerberosUser(hbaseConfig, 
kerberosUser);
+            kerberosUserReference.set(kerberosUser);
+            getLogger().info("Successfully logged in as principal {}", 
kerberosUser.getPrincipal());
+            return getUgi().doAs((PrivilegedExceptionAction<Connection>)() ->  
ConnectionFactory.createConnection(hbaseConfig));
+        } else {
+            getLogger().debug("Simple Authentication");
+            return ConnectionFactory.createConnection(hbaseConfig);
+        }
+    }
 
-            if (keyTab != null) {
-                kerberosUserReference.set(new KerberosKeytabUser(principal, 
keyTab));
-                getLogger().info("HBase Security Enabled, logging in as 
principal {} with keytab {}", new Object[] {principal, keyTab});
-            } else if (password != null) {
-                kerberosUserReference.set(new KerberosPasswordUser(principal, 
password));
-                getLogger().info("HBase Security Enabled, logging in as 
principal {} with password", new Object[] {principal});
-            } else {
-                throw new IOException("Unable to authenticate with Kerberos, 
no keytab or password was provided");
-            }
+    protected KerberosUser createKerberosUser(final ConfigurationContext 
context) {
+        // Check Kerberos User Service first, if present then get the 
KerberosUser from the service
+        // The customValidate method ensures that KerberosUserService can't be 
set at the same time as the credentials service or explicit properties
+        final KerberosUserService kerberosUserService = 
context.getProperty(KERBEROS_USER_SERVICE).asControllerService(KerberosUserService.class);
+        if (kerberosUserService != null) {
+            return kerberosUserService.createKerberosUser();
+        }
 
-            ugi = SecurityUtil.getUgiForKerberosUser(hbaseConfig, 
kerberosUserReference.get());
-            getLogger().info("Successfully logged in as principal " + 
principal);
+        String principal = 
context.getProperty(kerberosProperties.getKerberosPrincipal()).evaluateAttributeExpressions().getValue();
+        String keyTab = 
context.getProperty(kerberosProperties.getKerberosKeytab()).evaluateAttributeExpressions().getValue();
+        String password = 
context.getProperty(kerberosProperties.getKerberosPassword()).getValue();
 
-            return getUgi().doAs(new PrivilegedExceptionAction<Connection>() {
-                @Override
-                public Connection run() throws Exception {
-                    return ConnectionFactory.createConnection(hbaseConfig);
-                }
-            });
+        // If the Kerberos Credentials Service is specified, we need to use 
its configuration, not the explicit properties for principal/keytab.
+        // The customValidate method ensures that only one can be set, so we 
know that the principal & keytab above are null.
+        final KerberosCredentialsService credentialsService = 
context.getProperty(KERBEROS_CREDENTIALS_SERVICE).asControllerService(KerberosCredentialsService.class);
+        if (credentialsService != null) {
+            principal = credentialsService.getPrincipal();
+            keyTab = credentialsService.getKeytab();
+        }
 
+        if (keyTab != null) {
+            return new KerberosKeytabUser(principal, keyTab);
+        } else if (password != null) {
+            return new KerberosPasswordUser(principal, password);
         } else {
-            getLogger().info("Simple Authentication");
-            return ConnectionFactory.createConnection(hbaseConfig);
+            throw new IllegalStateException("Unable to authenticate with 
Kerberos, no keytab or password was provided");
         }
-
     }
 
     protected Configuration getConfigurationFromFiles(final String 
configFiles) {
@@ -413,8 +448,20 @@ public class HBase_2_ClientService extends 
AbstractControllerService implements
         if (connection != null) {
             try {
                 connection.close();
-            } catch (final IOException ioe) {
-                getLogger().warn("Failed to close connection to HBase due to 
{}", new Object[]{ioe});
+            } catch (final Exception e) {
+                getLogger().warn("HBase connection close failed", e);
+            }
+        }
+
+        final KerberosUser kerberosUser = kerberosUserReference.get();
+        if (kerberosUser != null) {
+            try {
+                kerberosUser.logout();
+            } catch (final Exception e) {
+                getLogger().warn("KeberosUser Logout Failed", e);
+            } finally {
+                ugi = null;
+                kerberosUserReference.set(null);
             }
         }
     }
@@ -891,6 +938,8 @@ public class HBase_2_ClientService extends 
AbstractControllerService implements
     }
 
     UserGroupInformation getUgi() throws IOException {
+        getLogger().trace("getting UGI instance");
+        // if there is a KerberosUser associated with UGI, call 
checkTGTAndRelogin to ensure UGI's underlying Subject has a valid ticket
         SecurityUtil.checkTGTAndRelogin(getLogger(), 
kerberosUserReference.get());
         return ugi;
     }
diff --git 
a/nifi-nar-bundles/nifi-standard-services/nifi-hbase_2-client-service-bundle/nifi-hbase_2-client-service/src/test/java/org/apache/nifi/hbase/TestHBase_2_ClientService.java
 
b/nifi-nar-bundles/nifi-standard-services/nifi-hbase_2-client-service-bundle/nifi-hbase_2-client-service/src/test/java/org/apache/nifi/hbase/TestHBase_2_ClientService.java
index e27a90c..1eb7b48 100644
--- 
a/nifi-nar-bundles/nifi-standard-services/nifi-hbase_2-client-service-bundle/nifi-hbase_2-client-service/src/test/java/org/apache/nifi/hbase/TestHBase_2_ClientService.java
+++ 
b/nifi-nar-bundles/nifi-standard-services/nifi-hbase_2-client-service-bundle/nifi-hbase_2-client-service/src/test/java/org/apache/nifi/hbase/TestHBase_2_ClientService.java
@@ -26,6 +26,8 @@ import org.apache.nifi.hbase.put.PutFlowFile;
 import org.apache.nifi.hbase.scan.Column;
 import org.apache.nifi.hbase.scan.ResultCell;
 import org.apache.nifi.hbase.scan.ResultHandler;
+import org.apache.nifi.kerberos.KerberosCredentialsService;
+import org.apache.nifi.kerberos.KerberosUserService;
 import org.apache.nifi.reporting.InitializationException;
 import org.apache.nifi.util.TestRunner;
 import org.apache.nifi.util.TestRunners;
@@ -49,6 +51,7 @@ import java.util.NavigableMap;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -178,6 +181,81 @@ public class TestHBase_2_ClientService {
         runner.setProperty(service, 
kerberosPropsWithoutFile.getKerberosKeytab(), "src/test/resources/fake.keytab");
         runner.setProperty(service, 
kerberosPropsWithoutFile.getKerberosPrincipal(), "test@REALM");
         runner.assertNotValid(service);
+
+        // Kerberos - add valid options with password
+        service = new MockHBaseClientService(table, COL_FAM, 
kerberosPropsWithFile, true);
+        runner.addControllerService("hbaseClientService", service);
+        runner.setProperty(service, HBase_2_ClientService.HADOOP_CONF_FILES,
+                "src/test/resources/hbase-site.xml, 
src/test/resources/core-site-security.xml");
+        runner.setProperty(service, 
kerberosPropsWithFile.getKerberosPassword(), "password");
+        runner.setProperty(service, 
kerberosPropsWithFile.getKerberosPrincipal(), "test@REALM");
+        runner.assertValid(service);
+
+        // Kerberos - keytab and password at same time should be invalid
+        runner.setProperty(service, kerberosPropsWithFile.getKerberosKeytab(), 
"src/test/resources/fake.keytab");
+        runner.assertNotValid(service);
+
+        runner.removeProperty(service, 
kerberosPropsWithFile.getKerberosKeytab());
+        runner.assertValid(service);
+
+        // Kerberos - credentials service not valid when other kerberos 
properties set
+        final KerberosCredentialsService credentialsService = 
enabledKerberosCredentialsService(runner);
+        runner.setProperty(service, 
HBase_2_ClientService.KERBEROS_CREDENTIALS_SERVICE, 
credentialsService.getIdentifier());
+        runner.assertNotValid(service);
+
+        runner.removeProperty(service, 
kerberosPropsWithFile.getKerberosPassword());
+        runner.assertNotValid(service);
+
+        runner.removeProperty(service, 
kerberosPropsWithFile.getKerberosPrincipal());
+        runner.assertValid(service);
+
+        runner.setProperty(service, kerberosPropsWithFile.getKerberosKeytab(), 
"src/test/resources/fake.keytab");
+        runner.assertNotValid(service);
+
+        runner.removeProperty(service, 
kerberosPropsWithFile.getKerberosKeytab());
+        runner.assertValid(service);
+
+        // Kerberos - user service with credentials service is invalid
+        final KerberosUserService userService = 
enableKerberosUserService(runner);
+        runner.setProperty(service, 
HBase_2_ClientService.KERBEROS_USER_SERVICE, userService.getIdentifier());
+        runner.assertNotValid(service);
+
+        runner.removeProperty(service, 
HBase_2_ClientService.KERBEROS_CREDENTIALS_SERVICE);
+        runner.assertValid(service);
+
+        // Kerberos - user service with other kerberos properties is invalid
+        runner.setProperty(service, 
kerberosPropsWithFile.getKerberosPassword(), "password");
+        runner.setProperty(service, 
kerberosPropsWithFile.getKerberosPrincipal(), "test@REALM");
+        runner.assertNotValid(service);
+
+        runner.removeProperty(service, 
kerberosPropsWithFile.getKerberosPassword());
+        runner.setProperty(service, kerberosPropsWithFile.getKerberosKeytab(), 
"src/test/resources/fake.keytab");
+        runner.assertNotValid(service);
+
+        runner.removeProperty(service, 
kerberosPropsWithFile.getKerberosKeytab());
+        runner.assertNotValid(service);
+
+        runner.removeProperty(service, 
kerberosPropsWithFile.getKerberosPrincipal());
+        runner.assertValid(service);
+    }
+
+    private KerberosUserService enableKerberosUserService(final TestRunner 
runner) throws InitializationException {
+        final KerberosUserService kerberosUserService = 
mock(KerberosUserService.class);
+        when(kerberosUserService.getIdentifier()).thenReturn("userService1");
+        runner.addControllerService(kerberosUserService.getIdentifier(), 
kerberosUserService);
+        runner.enableControllerService(kerberosUserService);
+        return kerberosUserService;
+    }
+
+    private KerberosCredentialsService enabledKerberosCredentialsService(final 
TestRunner runner) throws InitializationException {
+        final KerberosCredentialsService credentialsService = 
mock(KerberosCredentialsService.class);
+        when(credentialsService.getIdentifier()).thenReturn("credsService1");
+        when(credentialsService.getPrincipal()).thenReturn("principal1");
+        when(credentialsService.getKeytab()).thenReturn("keytab1");
+
+        runner.addControllerService(credentialsService.getIdentifier(), 
credentialsService);
+        runner.enableControllerService(credentialsService);
+        return credentialsService;
     }
 
     @Test
diff --git 
a/nifi-nar-bundles/nifi-standard-services/nifi-hwx-schema-registry-bundle/nifi-hwx-schema-registry-service/src/main/java/org/apache/nifi/schemaregistry/hortonworks/KerberosUserLogin.java
 
b/nifi-nar-bundles/nifi-standard-services/nifi-hwx-schema-registry-bundle/nifi-hwx-schema-registry-service/src/main/java/org/apache/nifi/schemaregistry/hortonworks/KerberosUserLogin.java
index d73f348..aac8960 100644
--- 
a/nifi-nar-bundles/nifi-standard-services/nifi-hwx-schema-registry-bundle/nifi-hwx-schema-registry-service/src/main/java/org/apache/nifi/schemaregistry/hortonworks/KerberosUserLogin.java
+++ 
b/nifi-nar-bundles/nifi-standard-services/nifi-hwx-schema-registry-bundle/nifi-hwx-schema-registry-service/src/main/java/org/apache/nifi/schemaregistry/hortonworks/KerberosUserLogin.java
@@ -46,7 +46,7 @@ public class KerberosUserLogin implements Login {
     }
 
     @Override
-    public LoginContext login() throws LoginException {
+    public LoginContext login() {
         kerberosUser.login();
 
         // the KerberosUser doesn't expose the LoginContext, but 
SchemaRegistryClient doesn't use
diff --git 
a/nifi-nar-bundles/nifi-standard-services/nifi-hwx-schema-registry-bundle/nifi-hwx-schema-registry-service/src/main/java/org/apache/nifi/schemaregistry/hortonworks/SchemaRegistryClientWithKerberosPassword.java
 
b/nifi-nar-bundles/nifi-standard-services/nifi-hwx-schema-registry-bundle/nifi-hwx-schema-registry-service/src/main/java/org/apache/nifi/schemaregistry/hortonworks/SchemaRegistryClientWithKerberosPassword.java
index ca84f8f..18eb77c 100644
--- 
a/nifi-nar-bundles/nifi-standard-services/nifi-hwx-schema-registry-bundle/nifi-hwx-schema-registry-service/src/main/java/org/apache/nifi/schemaregistry/hortonworks/SchemaRegistryClientWithKerberosPassword.java
+++ 
b/nifi-nar-bundles/nifi-standard-services/nifi-hwx-schema-registry-bundle/nifi-hwx-schema-registry-service/src/main/java/org/apache/nifi/schemaregistry/hortonworks/SchemaRegistryClientWithKerberosPassword.java
@@ -18,6 +18,7 @@ package org.apache.nifi.schemaregistry.hortonworks;
 
 import com.hortonworks.registries.schemaregistry.client.SchemaRegistryClient;
 import org.apache.nifi.logging.ComponentLog;
+import org.apache.nifi.security.krb.KerberosLoginException;
 import org.apache.nifi.security.krb.KerberosPasswordUser;
 import org.apache.nifi.security.krb.KerberosUser;
 import org.slf4j.Logger;
@@ -70,7 +71,7 @@ public class SchemaRegistryClientWithKerberosPassword extends 
SchemaRegistryClie
 
         try {
             login.login();
-        } catch (LoginException e) {
+        } catch (final KerberosLoginException | LoginException e) {
             LOGGER.error("Failed to login as principal `{}`", new 
Object[]{principal}, e);
         }
     }

Reply via email to