You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by mr...@apache.org on 2017/11/27 23:29:23 UTC

[11/30] ambari git commit: Merge trunk with feature branch and fix some UT compilation issues (mradhakrishnan)

http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/IPAKerberosOperationHandler.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/IPAKerberosOperationHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/IPAKerberosOperationHandler.java
index 9a6a07e..c411237 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/IPAKerberosOperationHandler.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/IPAKerberosOperationHandler.java
@@ -18,32 +18,14 @@
 
 package org.apache.ambari.server.serveraction.kerberos;
 
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.nio.charset.StandardCharsets;
-import java.text.NumberFormat;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
 import java.util.Map;
-import java.util.StringTokenizer;
-import java.util.TimeZone;
-import java.util.UUID;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import java.util.Set;
 
 import org.apache.ambari.server.security.credential.PrincipalKeyCredential;
-import org.apache.ambari.server.utils.Closeables;
 import org.apache.ambari.server.utils.ShellCommandUtil;
+import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang.StringUtils;
-import org.apache.directory.server.kerberos.shared.keytab.Keytab;
+import org.apache.directory.shared.kerberos.codec.types.EncryptionType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -54,12 +36,9 @@ import org.slf4j.LoggerFactory;
  * It is assumed that the IPA admin tools are installed and that the ipa shell command is
  * available
  */
-public class IPAKerberosOperationHandler extends KerberosOperationHandler {
+public class IPAKerberosOperationHandler extends KDCKerberosOperationHandler {
   private final static Logger LOG = LoggerFactory.getLogger(IPAKerberosOperationHandler.class);
 
-  private String adminServerHost = null;
-
-  private HashMap<String, Keytab> cachedKeytabs = null;
   /**
    * This is where user principals are members of. Important as the password should not expire
    * and thus a separate password policy should apply to this group
@@ -67,27 +46,6 @@ public class IPAKerberosOperationHandler extends KerberosOperationHandler {
   private String userPrincipalGroup = null;
 
   /**
-   * The format used for krbPasswordExpiry
-   */
-  private final SimpleDateFormat expiryFormat = new SimpleDateFormat("yyyyMMddHHmmss.SSS'Z'");
-
-  /**
-   * Time zone for krbPasswordExpiry
-   */
-  private static final TimeZone UTC = TimeZone.getTimeZone("UTC");
-
-  /**
-   * Years to add for password expiry
-   */
-  private static final int PASSWORD_EXPIRY_YEAR = 30;
-
-  /**
-   * A regular expression pattern to use to parse the key number from the text captured from the
-   * kvno command
-   */
-  private final static Pattern PATTERN_GET_KEY_NUMBER = Pattern.compile("^.*?: kvno = (\\d+).*$", Pattern.DOTALL);
-
-  /**
    * A String containing the resolved path to the ipa executable
    */
   private String executableIpaGetKeytab = null;
@@ -98,31 +56,6 @@ public class IPAKerberosOperationHandler extends KerberosOperationHandler {
   private String executableIpa = null;
 
   /**
-   * A String containing the resolved path to the kinit executable
-   */
-  private String executableKinit = null;
-
-  /**
-   * A String containing the resolved path to the ipa-getkeytab executable
-   */
-  private String executableKvno = null;
-
-  /**
-   * A boolean indicating if password expiry should be set
-   */
-  private boolean usePasswordExpiry = false;
-
-  /**
-   * An int indicating the time out in seconds for the password chat;
-   */
-  private int timeout = DEFAULT_PASSWORD_CHAT_TIMEOUT;
-
-  /**
-   * Credentials context stores a handler to the ccache so it can be reused and removed on request
-   */
-  private CredentialsContext credentialsContext;
-
-  /**
    * Prepares and creates resources to be used by this KerberosOperationHandler
    * <p/>
    * It is expected that this KerberosOperationHandler will not be used before this call.
@@ -139,84 +72,27 @@ public class IPAKerberosOperationHandler extends KerberosOperationHandler {
    * @throws KerberosOperationException           if an unexpected error occurred
    */
   @Override
-  public void open(PrincipalKeyCredential administratorCredentials, String realm,
-                   Map<String, String> kerberosConfiguration)
-          throws KerberosOperationException {
-
-    setAdministratorCredential(administratorCredentials);
-    setDefaultRealm(realm);
+  public void open(PrincipalKeyCredential administratorCredentials, String realm, Map<String, String> kerberosConfiguration)
+      throws KerberosOperationException {
 
     if (kerberosConfiguration != null) {
-      // todo: ignore if ipa managed krb5.conf?
-      setKeyEncryptionTypes(translateEncryptionTypes(kerberosConfiguration.get(KERBEROS_ENV_ENCRYPTION_TYPES), "\\s+"));
-      setExecutableSearchPaths(kerberosConfiguration.get(KERBEROS_ENV_EXECUTABLE_SEARCH_PATHS));
-      setUserPrincipalGroup(kerberosConfiguration.get(KERBEROS_ENV_USER_PRINCIPAL_GROUP));
-      setAdminServerHost(kerberosConfiguration.get(KERBEROS_ENV_ADMIN_SERVER_HOST));
-      setUsePasswordExpiry(kerberosConfiguration.get(KERBEROS_ENV_SET_PASSWORD_EXPIRY));
-      setTimeout(kerberosConfiguration.get(KERBEROS_ENV_PASSWORD_CHAT_TIMEOUT));
-    } else {
-      setKeyEncryptionTypes(null);
-      setAdminServerHost(null);
-      setExecutableSearchPaths((String) null);
-      setUserPrincipalGroup(null);
-      setUsePasswordExpiry(null);
-      setTimeout(null);
+      userPrincipalGroup = kerberosConfiguration.get(KERBEROS_ENV_USER_PRINCIPAL_GROUP);
     }
 
     // Pre-determine the paths to relevant Kerberos executables
     executableIpa = getExecutable("ipa");
-    executableKvno = getExecutable("kvno");
-    executableKinit = getExecutable("kinit");
     executableIpaGetKeytab = getExecutable("ipa-getkeytab");
 
-    credentialsContext = new CredentialsContext(administratorCredentials);
-    cachedKeytabs = new HashMap<>();
-    expiryFormat.setTimeZone(UTC);
-
-    setOpen(true);
-  }
-
-  private void setUsePasswordExpiry(String usePasswordExpiry) {
-    if (usePasswordExpiry == null) {
-      this.usePasswordExpiry = false;
-      return;
-    }
-
-    if (usePasswordExpiry.equalsIgnoreCase("true")) {
-      this.usePasswordExpiry = true;
-    } else {
-      this.usePasswordExpiry = false;
-    }
-  }
-
-  private void setTimeout(String timeout) {
-    if (timeout == null || timeout.isEmpty()) {
-      this.timeout = DEFAULT_PASSWORD_CHAT_TIMEOUT;
-      return;
-    }
-
-    try {
-      this.timeout = Integer.parseInt(timeout);
-    } catch (NumberFormatException e) {
-      this.timeout = DEFAULT_PASSWORD_CHAT_TIMEOUT;
-    }
+    super.open(administratorCredentials, realm, kerberosConfiguration);
   }
 
   @Override
   public void close() throws KerberosOperationException {
-    if (isOpen()) {
-      credentialsContext.delete();
-    }
-
-    // There is nothing to do here.
-    setOpen(false);
-
+    userPrincipalGroup = null;
     executableIpa = null;
-    executableKvno = null;
     executableIpaGetKeytab = null;
-    executableKinit = null;
-    credentialsContext = null;
-    cachedKeytabs = null;
+
+    super.close();
   }
 
   /**
@@ -226,190 +102,121 @@ public class IPAKerberosOperationHandler extends KerberosOperationHandler {
    * the result from STDOUT to determine if the presence of the specified principal.
    *
    * @param principal a String containing the principal to test
+   * @param service   a boolean value indicating whether the principal is for a service or not
    * @return true if the principal exists; false otherwise
    * @throws KerberosOperationException if an unexpected error occurred
    */
   @Override
-  public boolean principalExists(String principal)
-          throws KerberosOperationException {
-
-    LOG.debug("Entering principal exists");
+  public boolean principalExists(String principal, boolean service)
+      throws KerberosOperationException {
 
     if (!isOpen()) {
       throw new KerberosOperationException("This operation handler has not been opened");
     }
 
-    if (principal == null) {
-      return false;
-    } else if (isServicePrincipal(principal)) {
-      return true;
-    } else {
-      // TODO: fix exception check to only check for relevant exceptions
-      try {
-        DeconstructedPrincipal deconstructedPrincipal = createDeconstructPrincipal(principal);
-        LOG.debug("Running IPA command user-show");
+    if (!StringUtils.isEmpty(principal)) {
+      DeconstructedPrincipal deconstructedPrincipal = createDeconstructPrincipal(principal);
+      String principalName = deconstructedPrincipal.getPrincipalName();
 
-        // Create the ipa query to execute:
-        ShellCommandUtil.Result result = invokeIpa(String.format("user-show %s", deconstructedPrincipal.getPrincipalName()));
-        if (result.isSuccessful()) {
-          return true;
-        }
-      } catch (KerberosOperationException e) {
-        LOG.error("Cannot invoke IPA: " + e);
-        throw e;
+      String[] ipaCommand = new String[]{
+          (service) ? "service-show" : "user-show",
+          principalName
+      };
+
+      ShellCommandUtil.Result result = invokeIpa(ipaCommand);
+      if (result.isSuccessful()) {
+        return true;
       }
     }
 
     return false;
   }
 
-
   /**
-   * Creates a new principal in a previously configured IPA Realm
-   * <p/>
-   * This implementation creates a query to send to the kadmin shell command and then interrogates
-   * the result from STDOUT to determine if the operation executed successfully.
+   * Creates a new principal in a previously configured KDC.
+   * <p>
+   * This implementation uses the ipa shell to create either a user or service account.  No password
+   * will be set for either account type.  The password (or key) will be automatically generated by
+   * the IPA server when exporting the keytab entry.  Upon success, this method will always return
+   * <code>0</code> as the key number since the value is not generated until the keytab entry is
+   * exported.
    *
-   * @param principal a String containing the principal add
-   * @param password  a String containing the password to use when creating the principal
+   * @param principal a String containing the principal to add
+   * @param password  a String containing the password to use when creating the principal (ignored)
    * @param service   a boolean value indicating whether the principal is to be created as a service principal or not
-   * @return an Integer declaring the generated key number
-   * @throws KerberosKDCConnectionException if a connection to the KDC cannot be made
+   * @return an Integer declaring the generated key number (always 0)
+   * @throws KerberosOperationException
    */
   @Override
   public Integer createPrincipal(String principal, String password, boolean service)
-          throws KerberosOperationException {
+      throws KerberosOperationException {
 
     if (!isOpen()) {
       throw new KerberosOperationException("This operation handler has not been opened");
     }
 
-    if ((principal == null) || principal.isEmpty()) {
+    if (StringUtils.isEmpty(principal)) {
       throw new KerberosOperationException("Failed to create new principal - no principal specified");
-    } else if (((password == null) || password.isEmpty()) && service) {
-      throw new KerberosOperationException("Failed to create new user principal - no password specified");
-    } else {
-      DeconstructedPrincipal deconstructedPrincipal = createDeconstructPrincipal(principal);
-
-      if (service) {
-        // Create the ipa query:  service-add --ok-as-delegate <principal>
-        ShellCommandUtil.Result result = invokeIpa(String.format("service-add %s", principal));
-        if (result.isSuccessful()) {
-          // IPA does not generate encryption types when no keytab has been generated
-          // So getKeyNumber(principal) cannot be used.
-          // createKeytabCredentials(principal, password);
-          // return getKeyNumber(principal);
-          return 0;
-        } else {
-          LOG.error("Failed to execute ipa query: service-add --ok-as-delegate=TRUE {}\nSTDOUT: {}\nSTDERR: {}",
-                  principal, result.getStdout(), result.getStderr());
-          throw new KerberosOperationException(String.format("Failed to create service principal for %s\nSTDOUT: %s\nSTDERR: %s",
-                  principal, result.getStdout(), result.getStderr()));
-        }
-      } else {
-        if (!StringUtils.isAllLowerCase(deconstructedPrincipal.getPrincipalName())) {
-          LOG.warn(deconstructedPrincipal.getPrincipalName() + " is not in lowercase. FreeIPA does not recognize user " +
-                  "principals that are not entirely in lowercase. This can lead to issues with kinit and keytabs. Make " +
-                  "sure users are in lowercase ");
-        }
-        // Create the ipa query: user-add <username> --principal=<principal_name> --first <primary> --last <primary>
-        // set-attr userPassword="<password>"
-        // first and last are required for IPA so we make it equal to the primary
-        // the --principal arguments makes sure that Kerberos keys are available for use in getKeyNumber
-        ShellCommandUtil.Result result = invokeIpa(String.format("user-add %s --principal=%s --first %s --last %s --setattr userPassword=%s",
-                deconstructedPrincipal.getPrimary(), deconstructedPrincipal.getPrincipalName(),
-                deconstructedPrincipal.getPrimary(), deconstructedPrincipal.getPrimary(), password));
-
-        if (!result.isSuccessful()) {
-          throw new KerberosOperationException(String.format("Failed to create user principal for %s\nSTDOUT: %s\nSTDERR: %s",
-                  principal, result.getStdout(), result.getStderr()));
-        }
-
-        if (getUserPrincipalGroup() != null && !getUserPrincipalGroup().isEmpty()) {
-          result = invokeIpa(String.format("group-add-member %s --users=%s",
-                  getUserPrincipalGroup(), deconstructedPrincipal.getPrimary()));
-          if (!result.isSuccessful()) {
-            throw new KerberosOperationException(String.format("Failed to create user principal for %s\nSTDOUT: %s\nSTDERR: %s",
-                    principal, result.getStdout(), result.getStderr()));
-          }
-        }
-
-        if (!usePasswordExpiry) {
-          updatePassword(deconstructedPrincipal.getPrimary(), password);
-          return getKeyNumber(principal);
-        }
-
-        Calendar calendar = Calendar.getInstance();
-        calendar.add(Calendar.YEAR, PASSWORD_EXPIRY_YEAR);
+    }
 
-        result = invokeIpa(String.format("user-mod %s --setattr krbPasswordExpiration=%s",
-                deconstructedPrincipal.getPrimary(), expiryFormat.format(calendar.getTime())));
+    DeconstructedPrincipal deconstructedPrincipal = createDeconstructPrincipal(principal);
+    String normalizedPrincipal = deconstructedPrincipal.getNormalizedPrincipal();
 
-        if (result.isSuccessful()) {
-          return getKeyNumber(principal);
-        }
+    String[] ipaCommand;
+    if (service) {
+      ipaCommand = new String[]{
+          "service-add",
+          normalizedPrincipal
+      };
+    } else {
+      String principalName = deconstructedPrincipal.getPrincipalName();
 
-        throw new KerberosOperationException(String.format("Unknown error while creating principal for %s\n" +
-                        "STDOUT: %s\n" +
-                        "STDERR: %s\n",
-                principal, result.getStdout(), result.getStderr()));
+      if (!principalName.equals(principal.toLowerCase())) {
+        LOG.warn("{} is not in lowercase. FreeIPA does not recognize user " +
+            "principals that are not entirely in lowercase. This can lead to issues with kinit and keytabs. Make " +
+            "sure users are in lowercase.", principalName);
       }
-    }
-  }
 
-  /**
-   * Updates the password for an existing user principal in a previously configured IPA KDC
-   * <p/>
-   * This implementation creates a query to send to the ipa shell command and then interrogates
-   * the exit code to determine if the operation executed successfully.
-   *
-   * @param principal a String containing the principal to update
-   * @param password  a String containing the password to set
-   * @return an Integer declaring the new key number
-   * @throws KerberosOperationException if an unexpected error occurred
-   */
-  @Override
-  public Integer setPrincipalPassword(String principal, String password) throws KerberosOperationException {
-    if (!isOpen()) {
-      throw new KerberosOperationException("This operation handler has not been opened");
+      ipaCommand = new String[]{
+          "user-add",
+          deconstructedPrincipal.getPrimary(),
+          "--principal",
+          principalName,
+          "--first",
+          deconstructedPrincipal.getPrimary(),
+          "--last",
+          deconstructedPrincipal.getPrimary()
+      };
     }
 
-    if ((principal == null) || principal.isEmpty()) {
-      throw new KerberosOperationException("Failed to set password - no principal specified");
-    } else if ((password == null) || password.isEmpty()) {
-      throw new KerberosOperationException("Failed to set password - no password specified");
-    } else if (!isServicePrincipal(principal)) {
-      DeconstructedPrincipal deconstructedPrincipal = createDeconstructPrincipal(principal);
-
-      if (usePasswordExpiry) {
-        Calendar calendar = Calendar.getInstance();
-        calendar.add(Calendar.YEAR, PASSWORD_EXPIRY_YEAR);
+    ShellCommandUtil.Result result = invokeIpa(ipaCommand);
+    if (!result.isSuccessful()) {
+      String message = String.format("Failed to create principal for %s\n%s\nSTDOUT: %s\nSTDERR: %s",
+          normalizedPrincipal, StringUtils.join(ipaCommand, " "), result.getStdout(), result.getStderr());
+      LOG.error(message);
 
-        // Create the ipa query:  user-mod <user> --setattr userPassword=<password>
-        invokeIpa(String.format("user-mod %s --setattr userPassword=%s", deconstructedPrincipal.getPrimary(), password));
+      String stdErr = result.getStderr();
 
-        List<String> command = new ArrayList<>();
-        command.add(executableIpa);
-        command.add("user-mod");
-        command.add(deconstructedPrincipal.getPrimary());
-        command.add("--setattr");
-        command.add(String.format("krbPasswordExpiration=%s", expiryFormat.format(calendar.getTime())));
-        ShellCommandUtil.Result result = executeCommand(command.toArray(new String[command.size()]));
-        if (!result.isSuccessful()) {
-          throw new KerberosOperationException("Failed to set password expiry");
-        }
+      if ((stdErr != null) &&
+          ((service && stdErr.contains(String.format("service with name \"%s\" already exists", normalizedPrincipal))) ||
+          (!service && stdErr.contains(String.format("user with name \"%s\" already exists", deconstructedPrincipal.getPrimary()))))) {
+        throw new KerberosPrincipalAlreadyExistsException(principal);
       } else {
-        updatePassword(deconstructedPrincipal.getPrimary(), password);
+        throw new KerberosOperationException(String.format("Failed to create principal for %s\nSTDOUT: %s\nSTDERR: %s",
+            normalizedPrincipal, result.getStdout(), result.getStderr()));
       }
-    } else {
-      ShellCommandUtil.Result result = invokeIpa(String.format("service-show %s", principal));
-      // ignore the keytab but set the password for this principal
-      if (result.isSuccessful() && result.getStdout().contains("Keytab: False")) {
-        LOG.debug("Found service principal {} without password/keytab. Setting one", principal);
-        createKeytab(principal, password, 0);
+    }
+
+    if ((!service) && !StringUtils.isEmpty(userPrincipalGroup)) {
+      result = invokeIpa(new String[]{"group-add-member", userPrincipalGroup, "--users", deconstructedPrincipal.getPrimary()});
+      if (!result.isSuccessful()) {
+        LOG.warn("Failed to add account for {} to group {}: \nSTDOUT: {}\nSTDERR: {}",
+            normalizedPrincipal, userPrincipalGroup, result.getStdout(), result.getStderr());
       }
     }
-    return getKeyNumber(principal);
+
+    // Always return 0 since we do not have a key to get a key number for.
+    return 0;
   }
 
   /**
@@ -418,6 +225,7 @@ public class IPAKerberosOperationHandler extends KerberosOperationHandler {
    * The implementation is specific to a particular type of KDC.
    *
    * @param principal a String containing the principal to remove
+   * @param service   a boolean value indicating whether the principal is for a service or not
    * @return true if the principal was successfully removed; otherwise false
    * @throws KerberosKDCConnectionException       if a connection to the KDC cannot be made
    * @throws KerberosAdminAuthenticationException if the administrator credentials fail to authenticate
@@ -425,696 +233,95 @@ public class IPAKerberosOperationHandler extends KerberosOperationHandler {
    * @throws KerberosOperationException           if an unexpected error occurred
    */
   @Override
-  public boolean removePrincipal(String principal) throws KerberosOperationException {
+  public boolean removePrincipal(String principal, boolean service) throws KerberosOperationException {
     if (!isOpen()) {
       throw new KerberosOperationException("This operation handler has not been opened");
     }
 
-    if ((principal == null) || principal.isEmpty()) {
-      throw new KerberosOperationException("Failed to remove new principal - no principal specified");
-    } else {
-      ShellCommandUtil.Result result = null;
-      if (isServicePrincipal(principal)) {
-        result = invokeIpa(String.format("service-del %s", principal));
-      } else {
-        DeconstructedPrincipal deconstructedPrincipal = createDeconstructPrincipal(principal);
-        result = invokeIpa(String.format("user-del %s", deconstructedPrincipal.getPrincipalName()));
-      }
-      return result.isSuccessful();
+    if (StringUtils.isEmpty(principal)) {
+      throw new KerberosOperationException("Failed to remove principal - no principal specified");
     }
-  }
 
-  /**
-   * Sets the name of the group where user principals should be members of
-   *
-   * @param userPrincipalGroup the name of the group
-   */
-  public void setUserPrincipalGroup(String userPrincipalGroup) {
-    this.userPrincipalGroup = userPrincipalGroup;
-  }
+    DeconstructedPrincipal deconstructedPrincipal = createDeconstructPrincipal(principal);
 
-  /**
-   * Gets the name of the group where user principals should be members of
-   *
-   * @return name of the group where user principals should be members of
-   */
-  public String getUserPrincipalGroup() {
-    return this.userPrincipalGroup;
-  }
+    String[] ipaCommand = (service)
+        ? new String[]{"service-del", deconstructedPrincipal.getNormalizedPrincipal()}
+        : new String[]{"user-del", deconstructedPrincipal.getPrincipalName()};
 
-  /**
-   * Sets the KDC administrator server host address
-   *
-   * @param adminServerHost the ip address or FQDN of the IPA administrator server
-   */
-  public void setAdminServerHost(String adminServerHost) {
-    this.adminServerHost = adminServerHost;
+    return invokeIpa(ipaCommand).isSuccessful();
   }
 
-  /**
-   * Gets the IP address or FQDN of the IPA administrator server
-   *
-   * @return the IP address or FQDN of the IPA administrator server
-   */
-  public String getAdminServerHost() {
-    return this.adminServerHost;
+  @Override
+  protected String[] getKinitCommand(String executableKinit, PrincipalKeyCredential credentials, String credentialsCache) {
+    return new String[]{
+        executableKinit,
+        "-c",
+        credentialsCache,
+        credentials.getPrincipal()
+    };
   }
 
-  /**
-   * Reads data from a stream without blocking and when available. Allows some time for the
-   * stream to become ready.
-   *
-   * @param stdin  the stdin BufferedReader to read from
-   * @param stderr the stderr BufferedReader in case something goes wrong
-   * @return a String with available data
-   * @throws KerberosOperationException if a timeout happens
-   * @throws IOException                when somethings goes wrong with the underlying stream
-   * @throws InterruptedException       if the thread is interrupted
-   */
-  private String readData(BufferedReader stdin, BufferedReader stderr) throws KerberosOperationException, IOException, InterruptedException {
-    char[] data = new char[1024];
-    StringBuilder sb = new StringBuilder();
-
-    int count = 0;
-    while (!stdin.ready()) {
-      Thread.sleep(1000L);
-      if (count >= timeout) {
-        char[] err_data = new char[1024];
-        StringBuilder err = new StringBuilder();
-        while (stderr.ready()) {
-          stderr.read(err_data);
-          err.append(err_data);
+  @Override
+  protected void exportKeytabFile(String principal, String keytabFileDestinationPath, Set<EncryptionType> keyEncryptionTypes) throws KerberosOperationException {
+    String encryptionTypeSpec = null;
+    if (!CollectionUtils.isEmpty(keyEncryptionTypes)) {
+      StringBuilder encryptionTypeSpecBuilder = new StringBuilder();
+      for (EncryptionType encryptionType : keyEncryptionTypes) {
+        if (encryptionTypeSpecBuilder.length() > 0) {
+          encryptionTypeSpecBuilder.append(',');
         }
-        throw new KerberosOperationException("No answer data available from stdin stream. STDERR: " + err);
+        encryptionTypeSpecBuilder.append(encryptionType.getName());
       }
-      count++;
-    }
 
-    while (stdin.ready()) {
-      stdin.read(data);
-      sb.append(data);
+      encryptionTypeSpec = encryptionTypeSpecBuilder.toString();
     }
 
-    return sb.toString();
-  }
-
-  /**
-   * Updates a  password for a (user) principal. This is done by first setting a random password and
-   * then invoking kInit to directly set the password. This is done to circumvent issues with expired
-   * password in IPA, as IPA needs passwords set by the admin to be set again by the user. Note that
-   * this resets the current principal to the principal specified here. To invoke further administrative
-   * commands a new kInit to admin is required.
-   *
-   * @param principal The principal user name that needs to be updated
-   * @param password  The new password
-   * @throws KerberosOperationException if something is not as expected
-   */
-  private void updatePassword(String principal, String password) throws KerberosOperationException {
-    BufferedReader reader = null;
-    BufferedReader stderr = null;
-    OutputStreamWriter out = null;
-
-    LOG.debug("Updating password for: {}", principal);
-
-    UUID uuid = UUID.randomUUID();
-    String fileName = System.getProperty("java.io.tmpdir") +
-            File.pathSeparator +
-            "krb5cc_" + uuid;
-
-    try {
-      ShellCommandUtil.Result result = invokeIpa(String.format("user-mod %s --random", principal));
-      if (!result.isSuccessful()) {
-        throw new KerberosOperationException(result.getStderr());
-      }
-      Pattern pattern = Pattern.compile("password: (.*)");
-      Matcher matcher = pattern.matcher(result.getStdout());
-      if (!matcher.find()) {
-        throw new KerberosOperationException("Unexpected response from ipa: " + result.getStdout());
-      }
-      String old_password = matcher.group(1);
-
-      String credentialsCache = String.format("FILE:%s", fileName);
-      Process process = Runtime.getRuntime().exec(new String[]{executableKinit, "-c", credentialsCache, principal});
-      reader = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8));
-      stderr = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8));
-      out = new OutputStreamWriter(process.getOutputStream());
-
-      String data = readData(reader, stderr);
-      if (!data.startsWith("Password")) {
-        process.destroy();
-        throw new KerberosOperationException("Unexpected response from kinit while trying to password for "
-                + principal + " got: " + data);
-      }
-      LOG.debug("Sending old password");
-      out.write(old_password);
-      out.write('\n');
-      out.flush();
-
-      data = readData(reader, stderr);
-      if (!data.contains("Enter")) {
-        process.destroy();
-        throw new KerberosOperationException("Unexpected response from kinit while trying to password for "
-                + principal + " got: " + data);
-      }
-      LOG.debug("Sending new password");
-      out.write(password);
-      out.write('\n');
-      out.flush();
-
-      data = readData(reader, stderr);
-      if (!data.contains("again")) {
-        process.destroy();
-        throw new KerberosOperationException("Unexpected response from kinit while trying to password for "
-                + principal + " got: " + data);
-      }
-      LOG.debug("Sending new password again");
-      out.write(password);
-      out.write('\n');
-      out.flush();
+    String[] createKeytabFileCommand = (StringUtils.isEmpty(encryptionTypeSpec))
+        ? new String[]{executableIpaGetKeytab, "-s", getAdminServerHost(), "-p", principal, "-k", keytabFileDestinationPath}
+        : new String[]{executableIpaGetKeytab, "-s", getAdminServerHost(), "-e", encryptionTypeSpec, "-p", principal, "-k", keytabFileDestinationPath};
 
-      process.waitFor();
-    } catch (IOException e) {
-      LOG.error("Cannot read stream: " + e);
-      throw new KerberosOperationException(e.getMessage());
-    } catch (InterruptedException e) {
-      LOG.error("Process interrupted: " + e);
-      throw new KerberosOperationException(e.getMessage());
-    } finally {
-      try {
-        if (out != null)
-          out.close();
-      } catch (IOException e) {
-        LOG.warn("Cannot close out stream: " + e);
-      }
-      try {
-        if (reader != null)
-          reader.close();
-      } catch (IOException e) {
-        LOG.warn("Cannot close stdin stream: " + e);
-      }
-      try {
-        if (stderr != null)
-          stderr.close();
-      } catch (IOException e) {
-        LOG.warn("Cannot close stderr stream: " + e);
-      }
-      File ccache = new File(fileName);
-      ccache.delete();
+    ShellCommandUtil.Result result = executeCommand(createKeytabFileCommand);
+    if (!result.isSuccessful()) {
+      String message = String.format("Failed to export the keytab file for %s:\n\tExitCode: %s\n\tSTDOUT: %s\n\tSTDERR: %s",
+          principal, result.getExitCode(), result.getStdout(), result.getStderr());
+      LOG.warn(message);
+      throw new KerberosOperationException(message);
     }
-
   }
 
   /**
    * Invokes the ipa shell command with administrative credentials to issue queries
    *
-   * @param query a String containing the query to send to the kdamin command
+   * @param query a String containing the query to send to the ipa command
    * @return a ShellCommandUtil.Result containing the result of the operation
    * @throws KerberosOperationException if an unexpected error occurred
    */
-  protected ShellCommandUtil.Result invokeIpa(String query)
-          throws KerberosOperationException {
-    LOG.debug("Entering invokeipa");
+  private ShellCommandUtil.Result invokeIpa(String[] query) throws KerberosOperationException {
 
-    ShellCommandUtil.Result result = null;
-
-    if ((query == null) || query.isEmpty()) {
+    if ((query == null) || (query.length == 0)) {
       throw new KerberosOperationException("Missing ipa query");
     }
-    PrincipalKeyCredential administratorCredentials = getAdministratorCredential();
-    String defaultRealm = getDefaultRealm();
-
-    List<String> command = new ArrayList<>();
-    List<String> kinit = new ArrayList<>();
 
-    String adminPrincipal = (administratorCredentials == null)
-            ? null
-            : administratorCredentials.getPrincipal();
-
-    if ((adminPrincipal == null) || adminPrincipal.isEmpty()) {
-      throw new KerberosOperationException("No admin principal for ipa available - " +
-              "this KerberosOperationHandler may not have been opened.");
-    }
-
-    if ((executableIpa == null) || executableIpa.isEmpty()) {
-      throw new KerberosOperationException("No path for ipa is available - " +
-              "this KerberosOperationHandler may not have been opened.");
+    if (StringUtils.isEmpty(executableIpa)) {
+      throw new KerberosOperationException("No path for ipa is available - this KerberosOperationHandler may not have been opened.");
     }
 
-    // Set the ipa interface to be ipa
-    command.add(executableIpa);
-    command.add(query);
-
-    if (LOG.isDebugEnabled()) {
-      LOG.debug("Executing: {}", createCleanCommand(command));
-    }
+    String[] command = new String[query.length + 1];
+    command[0] = executableIpa;
+    System.arraycopy(query, 0, command, 1, query.length);
 
-    List<String> fixedCommand = fixCommandList(command);
-    result = executeCommand(fixedCommand.toArray(new String[fixedCommand.size()]));
-
-
-    LOG.debug("Done invokeipa");
-    return result;
-  }
+    ShellCommandUtil.Result result = executeCommand(command);
 
-  /**
-   * Executes a shell command in a credentials context
-   * <p/>
-   * See {@link org.apache.ambari.server.utils.ShellCommandUtil#runCommand(String[])}
-   *
-   * @param command an array of String value representing the command and its arguments
-   * @return a ShellCommandUtil.Result declaring the result of the operation
-   * @throws KerberosOperationException
-   */
-  @Override
-  protected ShellCommandUtil.Result executeCommand(String[] command)
-          throws KerberosOperationException {
-    return credentialsContext.executeCommand(command);
-  }
-
-  /**
-   * Rebuilds the command line to make sure space are converted to arguments
-   *
-   * @param command a List of items making up the command
-   * @return the fixed command
-   */
-  private List<String> fixCommandList(List<String> command) {
-    List<String> fixedCommandList = new ArrayList<>();
-    Iterator<String> iterator = command.iterator();
-
-    if (iterator.hasNext()) {
-      fixedCommandList.add(iterator.next());
-    }
-
-    while (iterator.hasNext()) {
-      String part = iterator.next();
-
-      // split arguments
-      if (part.contains(" ")) {
-        StringTokenizer st = new StringTokenizer(part, " ");
-        while (st.hasMoreElements()) {
-          fixedCommandList.add(st.nextToken());
-        }
-      } else {
-        fixedCommandList.add(part);
-      }
-    }
-
-    return fixedCommandList;
-  }
-
-  /**
-   * Build the ipa command string, replacing administrator password with "********"
-   *
-   * @param command a List of items making up the command
-   * @return the cleaned command string
-   */
-  private String createCleanCommand(List<String> command) {
-    StringBuilder cleanedCommand = new StringBuilder();
-    Iterator<String> iterator = command.iterator();
-
-    if (iterator.hasNext()) {
-      cleanedCommand.append(iterator.next());
-    }
-
-    while (iterator.hasNext()) {
-      String part = iterator.next();
-
-      cleanedCommand.append(' ');
-      cleanedCommand.append(part);
-
-      if ("--setattr".equals(part)) {
-        // Skip the password and use "********" instead
-        String arg= null;
-        if (iterator.hasNext()) {
-          arg = iterator.next();
-          if (arg.contains("userPassword")) {
-            cleanedCommand.append("userPassword=******");
-          } else {
-            cleanedCommand.append(arg);
-          }
-        }
-      }
-    }
-
-    return cleanedCommand.toString();
-  }
-
-  /**
-   * Determine is a principal is a service principal
-   *
-   * @param principal
-   * @return true if the principal is a (existing) service principal
-   * @throws KerberosOperationException
-   */
-  private boolean isServicePrincipal(String principal)
-          throws KerberosOperationException {
-
-    if ((principal == null) || principal.isEmpty()) {
-      throw new KerberosOperationException("Failed to determine principal type- no principal specified");
-    } else if (!principal.contains("/")) {
-      return false;
-    }
-
-    try {
-      ShellCommandUtil.Result result = invokeIpa(String.format("service-show %s", principal));
-
-      // TODO: unfortunately we can be in limbo if the "Keytab: False" is present
-      if (result.isSuccessful()) {
-        return true;
+    if (result.isSuccessful()) {
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("Executed the following command:\n{}\nSTDOUT: {}\nSTDERR: {}",
+            StringUtils.join(command, " "), result.getStdout(), result.getStderr());
       }
-    } catch (KerberosOperationException e) {
-      LOG.warn("Exception while invoking ipa service-show: " + e);
-      return false;
-    }
-
-    return false;
-  }
-
-  /**
-   * Retrieves the current key number assigned to the identity identified by the specified principal
-   *
-   * @param principal a String declaring the principal to look up
-   * @return an Integer declaring the current key number
-   * @throws KerberosKDCConnectionException       if a connection to the KDC cannot be made
-   * @throws KerberosAdminAuthenticationException if the administrator credentials fail to authenticate
-   * @throws KerberosRealmException               if the realm does not map to a KDC
-   * @throws KerberosOperationException           if an unexpected error occurred
-   */
-  private Integer getKeyNumber(String principal) throws KerberosOperationException {
-    if (!isOpen()) {
-      throw new KerberosOperationException("This operation handler has not been opened");
-    }
-
-    if ((principal == null) || principal.isEmpty()) {
-      throw new KerberosOperationException("Failed to get key number for principal  - no principal specified");
     } else {
-      // Create the kvno query:  <principal>
-      List<String> command = new ArrayList<>();
-      command.add(executableKvno);
-      command.add(principal);
-
-      ShellCommandUtil.Result result = executeCommand(command.toArray(new String[command.size()]));
-      String stdOut = result.getStdout();
-      if (stdOut == null) {
-        String message = String.format("Failed to get key number for %s:\n\tExitCode: %s\n\tSTDOUT: NULL\n\tSTDERR: %s",
-                principal, result.getExitCode(), result.getStderr());
-        LOG.warn(message);
-        throw new KerberosOperationException(message);
-      }
-
-      Matcher matcher = PATTERN_GET_KEY_NUMBER.matcher(stdOut);
-      if (matcher.matches()) {
-        NumberFormat numberFormat = NumberFormat.getIntegerInstance();
-        String keyNumber = matcher.group(1);
-
-        numberFormat.setGroupingUsed(false);
-        try {
-          Number number = numberFormat.parse(keyNumber);
-          return (number == null) ? 0 : number.intValue();
-        } catch (ParseException e) {
-          String message = String.format("Failed to get key number for %s - invalid key number value (%s):\n\tExitCode: %s\n\tSTDOUT: NULL\n\tSTDERR: %s",
-                  principal, keyNumber, result.getExitCode(), result.getStderr());
-          LOG.warn(message);
-          throw new KerberosOperationException(message);
-        }
-      } else {
-        String message = String.format("Failed to get key number for %s - unexpected STDOUT data:\n\tExitCode: %s\n\tSTDOUT: NULL\n\tSTDERR: %s",
-                principal, result.getExitCode(), result.getStderr());
-        LOG.warn(message);
-        throw new KerberosOperationException(message);
-      }
-
-    }
-  }
-
-  /*
-   * Creates a key tab by using the ipa commandline utilities.
-   *
-   * @param principal a String containing the principal to test
-   * @param password  a String containing the password to use when creating the principal
-   * @return
-   * @throws KerberosOperationException
-   */
-  /*private Keytab createKeytabCredentials(String principal, String password)
-          throws KerberosOperationException {
-
-    if ((principal == null) || principal.isEmpty()) {
-      throw new KerberosOperationException("Failed to create keytab file, missing principal");
-    }
-
-    BufferedReader reader = null;
-    BufferedReader stderr = null;
-    OutputStreamWriter out = null;
-
-    UUID uuid = UUID.randomUUID();
-    String fileName = System.getProperty("java.io.tmpdir") +
-            File.pathSeparator +
-            "ambari." + uuid.toString();
-
-    try {
-      // TODO: add ciphers
-      Process p = credentialsContext.exec(new String[]{executableIpaGetKeytab, "-s",
-              getAdminServerHost(), "-p", principal, "-k", fileName, "-P"});
-      reader = new BufferedReader(new InputStreamReader(p.getInputStream(), StandardCharsets.UTF_8));
-      stderr = new BufferedReader(new InputStreamReader(p.getErrorStream(), StandardCharsets.UTF_8));
-      out = new OutputStreamWriter(p.getOutputStream());
-
-      String data = readData(reader, stderr);
-      if (!data.startsWith("New")) {
-        p.destroy();
-        throw new KerberosOperationException("Unexpected response from ipa-getkeytab while trying to password for "
-                + principal + " got: " + data);
-      }
-      LOG.debug("Sending password");
-      out.write(password);
-      out.write('\n');
-      out.flush();
-
-      data = readData(reader, stderr);
-      if (!data.contains("Verify")) {
-        p.destroy();
-        throw new KerberosOperationException("Unexpected response from ipa-getkeytab while trying to password for "
-                + principal + " got: " + data);
-      }
-      LOG.debug("Sending new password");
-      out.write(password);
-      out.write('\n');
-      out.flush();
-
-      p.waitFor();
-    } catch (IOException e) {
-      LOG.error("Cannot read stream: " + e);
-      throw new KerberosOperationException(e.getMessage());
-    } catch (InterruptedException e) {
-      LOG.error("Process interrupted: " + e);
-      throw new KerberosOperationException(e.getMessage());
-    } finally {
-      try {
-        if (out != null)
-          out.close();
-      } catch (IOException e) {
-        LOG.warn("Cannot close out stream: " + e);
-      }
-      try {
-        if (reader != null)
-          reader.close();
-      } catch (IOException e) {
-        LOG.warn("Cannot close stdin stream: " + e);
-      }
-      try {
-        if (stderr != null)
-          stderr.close();
-      } catch (IOException e) {
-        LOG.warn("Cannot close stderr stream: " + e);
-      }
-    }
-
-    File keytabFile = new File(fileName);
-    Keytab keytab = readKeytabFile(keytabFile);
-    keytabFile.delete();
-
-    return keytab;
-  }*/
-
-  /**
-   * Creates a key tab by using the ipa commandline utilities. It ignores key number and password
-   * as this will be handled by IPA
-   *
-   * @param principal a String containing the principal to test
-   * @param password  (IGNORED) a String containing the password to use when creating the principal
-   * @param keyNumber (IGNORED) a Integer indicating the key number for the keytab entries
-   * @return
-   * @throws KerberosOperationException
-   */
-  @Override
-  protected Keytab createKeytab(String principal, String password, Integer keyNumber)
-          throws KerberosOperationException {
-
-    if ((principal == null) || principal.isEmpty()) {
-      throw new KerberosOperationException("Failed to create keytab file, missing principal");
-    }
-
-    // use cache if available
-    if (cachedKeytabs.containsKey(principal)) {
-      return cachedKeytabs.get(principal);
-    }
-
-    UUID uuid = UUID.randomUUID();
-    String fileName = System.getProperty("java.io.tmpdir") +
-            File.pathSeparator +
-            "ambari." + uuid;
-
-    // TODO: add ciphers
-    List<String> command = new ArrayList<>();
-    command.add(executableIpaGetKeytab);
-    command.add("-s");
-    command.add(getAdminServerHost());
-    command.add("-p");
-    command.add(principal);
-    command.add("-k");
-    command.add(fileName);
-
-    // TODO: is it really required to set the password?
-    ShellCommandUtil.Result result = executeCommand(command.toArray(new String[command.size()]));
-    if (!result.isSuccessful()) {
-      String message = String.format("Failed to get key number for %s:\n\tExitCode: %s\n\tSTDOUT: %s\n\tSTDERR: %s",
-              principal, result.getExitCode(), result.getStdout(), result.getStderr());
-      LOG.warn(message);
-      throw new KerberosOperationException(message);
-    }
-
-    File keytabFile = new File(fileName);
-    Keytab keytab = readKeytabFile(keytabFile);
-    keytabFile.delete();
-
-    cachedKeytabs.put(principal, keytab);
-    return keytab;
-  }
-
-
-  /**
-   * Credentials context executes commands wrapped with kerberos credentials
-   */
-  class CredentialsContext {
-    private PrincipalKeyCredential credentials;
-    Map<String, String> env = new HashMap<>();
-    private String fileName;
-    private List<Process> processes = new ArrayList<>();
-
-    public CredentialsContext(PrincipalKeyCredential credentials) throws KerberosOperationException {
-      this.credentials = credentials;
-
-      UUID uuid = UUID.randomUUID();
-      fileName = System.getProperty("java.io.tmpdir") +
-              File.pathSeparator +
-              "krb5cc_" + uuid;
-      env.put("KRB5CCNAME", String.format("FILE:%s", fileName));
-
-      init(credentials, fileName);
-    }
-
-    protected ShellCommandUtil.Result executeCommand(String[] command)
-            throws KerberosOperationException {
-
-      if ((command == null) || (command.length == 0)) {
-        return null;
-      } else {
-        try {
-          return ShellCommandUtil.runCommand(command, env);
-        } catch (IOException e) {
-          String message = String.format("Failed to execute the command: %s", e.getLocalizedMessage());
-          LOG.error(message, e);
-          throw new KerberosOperationException(message, e);
-        } catch (InterruptedException e) {
-          String message = String.format("Failed to wait for the command to complete: %s", e.getLocalizedMessage());
-          LOG.error(message, e);
-          throw new KerberosOperationException(message, e);
-        }
-      }
-    }
-
-    /**
-     * Does a kinit to obtain a ticket for the specified principal and stores it in the specified cache
-     *
-     * @param credentials Credentials to be used to obtain the ticket
-     * @param fileName    Filename where to store the credentials
-     * @throws KerberosOperationException In case the ticket cannot be obtained
-     */
-    private void init(PrincipalKeyCredential credentials, String fileName) throws KerberosOperationException {
-      Process process;
-      BufferedReader reader = null;
-      OutputStreamWriter osw = null;
-
-      LOG.debug("Entering doKinit");
-      try {
-        String credentialsCache = String.format("FILE:%s", fileName);
-
-        LOG.debug("start subprocess {} {}", executableKinit, credentials.getPrincipal());
-        process = Runtime.getRuntime().exec(new String[]{executableKinit, "-c", credentialsCache, credentials.getPrincipal()});
-        reader = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8));
-        osw = new OutputStreamWriter(process.getOutputStream());
-
-        char[] data = new char[1024];
-        StringBuilder sb = new StringBuilder();
-
-        int count = 0;
-        while (!reader.ready()) {
-          Thread.sleep(1000L);
-          if (count >= 5) {
-            process.destroy();
-            throw new KerberosOperationException("No answer from kinit");
-          }
-          count++;
-        }
-
-        while (reader.ready()) {
-          reader.read(data);
-          sb.append(data);
-        }
-
-        String line = sb.toString();
-        LOG.debug("Reading a line: {}", line);
-        if (!line.startsWith("Password")) {
-          throw new KerberosOperationException("Unexpected response from kinit while trying to get ticket for "
-                  + credentials.getPrincipal() + " got: " + line);
-        }
-        osw.write(credentials.getKey());
-        osw.write('\n');
-        osw.close();
-
-        process.waitFor();
-
-        LOG.debug("done subprocess");
-      } catch (IOException | InterruptedException e) {
-        String message = String.format("Failed to execute the command: %s", e.getLocalizedMessage());
-        LOG.error(message, e);
-        throw new KerberosOperationException(message, e);
-      } finally {
-        Closeables.closeSilently(osw);
-        Closeables.closeSilently(reader);
-      }
-
-      if (process.exitValue() != 0) {
-        throw new KerberosOperationException("kinit failed for " + credentials.getPrincipal() + ". Wrong password?");
-      }
-
-    }
-
-    public Process exec(String[] args) throws IOException {
-      Process process = Runtime.getRuntime().exec(args);
-      processes.add(process);
-
-      return process;
-    }
-
-    public void delete() {
-      File ccache = new File(fileName);
-      ccache.delete();
-      for (Process p : processes) {
-        p.destroy();
-      }
+      LOG.error("Failed to execute the following command:\n{}\nSTDOUT: {}\nSTDERR: {}",
+          StringUtils.join(command, " "), result.getStdout(), result.getStderr());
     }
 
+    return result;
   }
-
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KDCKerberosOperationHandler.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KDCKerberosOperationHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KDCKerberosOperationHandler.java
new file mode 100644
index 0000000..bf3ac22
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KDCKerberosOperationHandler.java
@@ -0,0 +1,391 @@
+/*
+ * 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.ambari.server.serveraction.kerberos;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.security.credential.PrincipalKeyCredential;
+import org.apache.ambari.server.utils.ShellCommandUtil;
+import org.apache.commons.collections.MapUtils;
+import org.apache.directory.server.kerberos.shared.keytab.Keytab;
+import org.apache.directory.shared.kerberos.codec.types.EncryptionType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * KDCKerberosOperationHandler is an implementation of a KerberosOperationHandler providing
+ * functionality KDC-based Kerberos providers.
+ * <p>
+ * This implementation provides kinit functionality and keytab file caching utilities for classes.
+ */
+abstract class KDCKerberosOperationHandler extends KerberosOperationHandler {
+  private static final Logger LOG = LoggerFactory.getLogger(KDCKerberosOperationHandler.class);
+
+  /**
+   * The FQDN of the host where KDC administration server is
+   */
+  private String adminServerHost = null;
+
+  /**
+   * A map of principal names to {@link Keytab} entries to ensure a Keyab file is not created/exported
+   * for the same principal more than once.
+   */
+  private HashMap<String, Keytab> cachedKeytabs = null;
+
+  /**
+   * A String containing the resolved path to the kinit executable
+   */
+  private String executableKinit = null;
+
+  /**
+   * The absolute path to the KDC administrator's Kerberos ticket cache.
+   * <p>
+   * This path is created as as temporary file with a randomized name when this {@link KerberosOperationHandler}
+   * is open.  It is destoryed when this {@link KerberosOperationHandler} is closed.
+   */
+  private File credentialsCacheFile = null;
+
+  /**
+   * A Map of environmet values to send to system command invocations.
+   * <p>
+   * This map is to be appened to any map of environment values passed in when
+   * invoking {@link KerberosOperationHandler#executeCommand(String[], Map, ShellCommandUtil.InteractiveHandler)}
+   */
+  private Map<String, String> environmentMap = null;
+
+  @Override
+  public void open(PrincipalKeyCredential administratorCredentials, String realm, Map<String, String> kerberosConfiguration)
+      throws KerberosOperationException {
+
+    super.open(administratorCredentials, realm, kerberosConfiguration);
+
+    if (kerberosConfiguration != null) {
+      adminServerHost = kerberosConfiguration.get(KERBEROS_ENV_ADMIN_SERVER_HOST);
+    }
+
+    // Pre-determine the paths to relevant Kerberos executables
+    executableKinit = getExecutable("kinit");
+
+    setOpen(init());
+  }
+
+  @Override
+  public void close() throws KerberosOperationException {
+
+    if (credentialsCacheFile != null) {
+      if (credentialsCacheFile.delete()) {
+        LOG.debug("Failed to remove the cache file, {}", credentialsCacheFile.getAbsolutePath());
+      }
+      credentialsCacheFile = null;
+    }
+
+    environmentMap = null;
+    executableKinit = null;
+    cachedKeytabs = null;
+    adminServerHost = null;
+
+    super.close();
+  }
+
+  /**
+   * Updates the password for an existing user principal in a previously configured IPA KDC
+   * <p/>
+   * This implementation creates a query to send to the ipa shell command and then interrogates
+   * the exit code to determine if the operation executed successfully.
+   *
+   * @param principal a String containing the principal to update
+   * @param password  a String containing the password to set
+   * @param service   a boolean value indicating whether the principal is for a service or not
+   * @return an Integer declaring the new key number
+   * @throws KerberosOperationException if an unexpected error occurred
+   */
+  @Override
+  public Integer setPrincipalPassword(String principal, String password, boolean service) throws KerberosOperationException {
+    if (!isOpen()) {
+      throw new KerberosOperationException("This operation handler has not been opened");
+    }
+
+    // It is expected that KerberosPrincipalDoesNotExistException is thrown if the principal does not exist.
+    // The caller expects so that it can attempt to set the password for a principal without checking
+    // to see if it exists first. If the principal does not exist and is required, the caller will
+    // create it.  This saves a potentially unnecessary round trip to the KDC and back.
+    if(!principalExists(principal, service)) {
+      throw new KerberosPrincipalDoesNotExistException(String.format("Principal does not exist while attempting to set its password: %s", principal));
+    }
+
+    // This operation does nothing since a new key will be created when exporting the keytab file...
+    return 0;
+  }
+
+  /**
+   * Creates a key tab by using the ipa commandline utilities. It ignores key number and password
+   * as this will be handled by IPA
+   *
+   * @param principal a String containing the principal to test
+   * @param password  (IGNORED) a String containing the password to use when creating the principal
+   * @param keyNumber (IGNORED) a Integer indicating the key number for the keytab entries
+   * @return the created Keytab
+   * @throws KerberosOperationException
+   */
+  @Override
+  protected Keytab createKeytab(String principal, String password, Integer keyNumber)
+      throws KerberosOperationException {
+
+    if ((principal == null) || principal.isEmpty()) {
+      throw new KerberosOperationException("Failed to create keytab file, missing principal");
+    }
+
+    // use cache if available
+    if (cachedKeytabs.containsKey(principal)) {
+      return cachedKeytabs.get(principal);
+    }
+
+    File keytabFile = null;
+
+    try {
+      try {
+        keytabFile = File.createTempFile("ambari_tmp", ".keytab");
+
+        // Remove the file else the command will fail...
+        if (!keytabFile.delete()) {
+          LOG.warn("Failed to remove temporary file to hold keytab.  Exporting the keytab file for {} may fail.", principal);
+        }
+      } catch (IOException e) {
+        throw new KerberosOperationException(String.format("Failed to create the temporary file needed to hold the exported keytab file for %s: %s", principal, e.getLocalizedMessage()), e);
+      }
+
+
+      exportKeytabFile(principal, keytabFile.getAbsolutePath(), getKeyEncryptionTypes());
+
+      Keytab keytab = readKeytabFile(keytabFile);
+      cachedKeytabs.put(principal, keytab);
+      return keytab;
+    } finally {
+      if ((keytabFile != null) && keytabFile.exists()) {
+        if (!keytabFile.delete()) {
+          LOG.debug("Failed to remove the temporary keytab file, {}", keytabFile.getAbsolutePath());
+        }
+      }
+    }
+  }
+
+  /**
+   * Executes a shell command in a credentials context
+   * <p/>
+   * See {@link ShellCommandUtil#runCommand(String[])}
+   * <p>
+   * This implementation sets the proper environment for the custom <code>KRB5CCNAME </code> value.
+   *
+   * @param command            an array of String value representing the command and its arguments
+   * @param envp               a map of string, string of environment variables
+   * @param interactiveHandler a handler to provide responses to queries from the command,
+   *                           or null if no queries are expected
+   * @return a ShellCommandUtil.Result declaring the result of the operation
+   * @throws KerberosOperationException
+   */
+  @Override
+  protected ShellCommandUtil.Result executeCommand(String[] command, Map<String, String> envp, ShellCommandUtil.InteractiveHandler interactiveHandler)
+      throws KerberosOperationException {
+
+    Map<String, String> _envp;
+
+    if (MapUtils.isEmpty(environmentMap)) {
+      _envp = envp;
+    } else if (MapUtils.isEmpty(envp)) {
+      _envp = environmentMap;
+    } else {
+      _envp = new HashMap<>();
+      _envp.putAll(envp);
+      _envp.putAll(environmentMap);
+    }
+
+    return super.executeCommand(command, _envp, interactiveHandler);
+  }
+
+  String getAdminServerHost() {
+    return adminServerHost;
+  }
+
+  String getCredentialCacheFilePath() {
+    return (credentialsCacheFile == null) ? null : credentialsCacheFile.getAbsolutePath();
+  }
+
+  /**
+   * Return an array of Strings containing the command and the relavant arguments needed authenticate
+   * with the KDC and create the Kerberos ticket/credential cache.
+   *
+   * @param executableKinit  the absolute path to the kinit executable
+   * @param credentials      the KDC adminisrator's credentials
+   * @param credentialsCache the absolute path to the expected location of the Kerberos ticket/credential cache file
+   * @return an array of Strings containing the command to execute
+   */
+  protected abstract String[] getKinitCommand(String executableKinit, PrincipalKeyCredential credentials, String credentialsCache);
+
+  /**
+   * Export the requested keytab entries for a given principal into the specified file.
+   *
+   * @param principal                 the principal name
+   * @param keytabFileDestinationPath the absolute path to the keytab file
+   * @param keyEncryptionTypes        a collection of encrption algorithm types indicating which ketyab entries are requested
+   * @throws KerberosOperationException
+   */
+  protected abstract void exportKeytabFile(String principal, String keytabFileDestinationPath, Set<EncryptionType> keyEncryptionTypes) throws KerberosOperationException;
+
+  /**
+   * Initialize the Kerberos ticket cache using the supplied KDC administrator's credentials.
+   * <p>
+   * A randomly named temporary file is created to store the Kerberos ticket cache for this {@link KerberosOperationHandler}'s
+   * session. The file will be removed upon closing when the session is complete.  The geneated ticket cache
+   * filename is set in the environment variable map using the variable name "KRB5CCNAME". This will be passed
+   * in for all relevant-system commands.
+   *
+   * @return
+   * @throws KerberosOperationException
+   */
+  protected boolean init() throws KerberosOperationException {
+    if (credentialsCacheFile != null) {
+      if (!credentialsCacheFile.delete()) {
+        LOG.debug("Failed to remove the orphaned cache file, {}", credentialsCacheFile.getAbsolutePath());
+      }
+      credentialsCacheFile = null;
+    }
+
+    try {
+      credentialsCacheFile = File.createTempFile("ambari_krb_", "cc");
+      credentialsCacheFile.deleteOnExit();
+      ensureAmbariOnlyAccess(credentialsCacheFile);
+    } catch (IOException e) {
+      throw new KerberosOperationException(String.format("Failed to create the temporary file needed to hold the administrator ticket cache: %s", e.getLocalizedMessage()), e);
+    }
+
+    String credentialsCache = String.format("FILE:%s", credentialsCacheFile.getAbsolutePath());
+
+    environmentMap = new HashMap<>();
+    environmentMap.put("KRB5CCNAME", credentialsCache);
+
+    PrincipalKeyCredential credentials = getAdministratorCredential();
+
+    ShellCommandUtil.Result result = executeCommand(getKinitCommand(executableKinit, credentials, credentialsCache),
+        environmentMap,
+        new InteractivePasswordHandler(String.valueOf(credentials.getKey()), null));
+
+    if (!result.isSuccessful()) {
+      String message = String.format("Failed to kinit as the KDC administrator user, %s:\n\tExitCode: %s\n\tSTDOUT: %s\n\tSTDERR: %s",
+          credentials.getPrincipal(), result.getExitCode(), result.getStdout(), result.getStderr());
+      LOG.warn(message);
+      throw new KerberosAdminAuthenticationException(message);
+    }
+
+    cachedKeytabs = new HashMap<>();
+
+    return true;
+  }
+
+  /**
+   * Ensures that the owner of the Ambari server process is the only local user account able to
+   * read and write to the specified file or read, write to, and execute the specified directory.
+   *
+   * @param file the file or directory for which to modify access
+   */
+  private void ensureAmbariOnlyAccess(File file) throws AmbariException {
+    if (file.exists()) {
+      if (!file.setReadable(false, false) || !file.setReadable(true, true)) {
+        String message = String.format("Failed to set %s readable only by Ambari", file.getAbsolutePath());
+        LOG.warn(message);
+        throw new AmbariException(message);
+      }
+
+      if (!file.setWritable(false, false) || !file.setWritable(true, true)) {
+        String message = String.format("Failed to set %s writable only by Ambari", file.getAbsolutePath());
+        LOG.warn(message);
+        throw new AmbariException(message);
+      }
+
+      if (file.isDirectory()) {
+        if (!file.setExecutable(false, false) || !file.setExecutable(true, true)) {
+          String message = String.format("Failed to set %s executable by Ambari", file.getAbsolutePath());
+          LOG.warn(message);
+          throw new AmbariException(message);
+        }
+      } else {
+        if (!file.setExecutable(false, false)) {
+          String message = String.format("Failed to set %s not executable", file.getAbsolutePath());
+          LOG.warn(message);
+          throw new AmbariException(message);
+        }
+      }
+    }
+  }
+
+  /**
+   * InteractivePasswordHandler is a {@link ShellCommandUtil.InteractiveHandler}
+   * implementation that answers queries from kadmin or kdamin.local command for the admin and/or user
+   * passwords.
+   */
+  protected static class InteractivePasswordHandler implements ShellCommandUtil.InteractiveHandler {
+    /**
+     * The queue of responses to return
+     */
+    private LinkedList<String> responses;
+    private Queue<String> currentResponses;
+
+    /**
+     * Constructor.
+     *
+     * @param adminPassword the KDC administrator's password (optional)
+     * @param userPassword  the user's password (optional)
+     */
+    InteractivePasswordHandler(String adminPassword, String userPassword) {
+      responses = new LinkedList<>();
+
+      if (adminPassword != null) {
+        responses.offer(adminPassword);
+      }
+
+      if (userPassword != null) {
+        responses.offer(userPassword);
+        responses.offer(userPassword);  // Add a 2nd time for the password "confirmation" request
+      }
+
+      currentResponses = new LinkedList<>(responses);
+    }
+
+    @Override
+    public boolean done() {
+      return currentResponses.size() == 0;
+    }
+
+    @Override
+    public String getResponse(String query) {
+      return currentResponses.poll();
+    }
+
+    @Override
+    public void start() {
+      currentResponses = new LinkedList<>(responses);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosIdentityDataFile.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosIdentityDataFile.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosIdentityDataFile.java
index ddf3d1b..ae1217c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosIdentityDataFile.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosIdentityDataFile.java
@@ -36,6 +36,4 @@ public interface KerberosIdentityDataFile extends KerberosDataFile {
   String KEYTAB_FILE_GROUP_NAME = "keytab_file_group_name";
   String KEYTAB_FILE_GROUP_ACCESS = "keytab_file_group_access";
   String KEYTAB_FILE_IS_CACHABLE = "keytab_file_is_cachable";
-  String ONLY_KEYTAB_WRITE = "only_keytab_write";
-
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosIdentityDataFileWriter.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosIdentityDataFileWriter.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosIdentityDataFileWriter.java
index ea742bd..f55c6f4 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosIdentityDataFileWriter.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosIdentityDataFileWriter.java
@@ -68,8 +68,7 @@ public class KerberosIdentityDataFileWriter extends AbstractKerberosDataFileWrit
                           String principal, String principalType,
                           String keytabFilePath, String keytabFileOwnerName,
                           String keytabFileOwnerAccess, String keytabFileGroupName,
-                          String keytabFileGroupAccess, String keytabFileCanCache,
-                          String onlyKeytabWrite)
+                          String keytabFileGroupAccess, String keytabFileCanCache)
       throws IOException {
     super.appendRecord(hostName,
         serviceName,
@@ -81,8 +80,7 @@ public class KerberosIdentityDataFileWriter extends AbstractKerberosDataFileWrit
         keytabFileOwnerAccess,
         keytabFileGroupName,
         keytabFileGroupAccess,
-        keytabFileCanCache,
-        onlyKeytabWrite);
+        keytabFileCanCache);
   }
 
   @Override
@@ -97,7 +95,6 @@ public class KerberosIdentityDataFileWriter extends AbstractKerberosDataFileWrit
         KEYTAB_FILE_OWNER_ACCESS,
         KEYTAB_FILE_GROUP_NAME,
         KEYTAB_FILE_GROUP_ACCESS,
-        KEYTAB_FILE_IS_CACHABLE,
-        ONLY_KEYTAB_WRITE);
+        KEYTAB_FILE_IS_CACHABLE);
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosOperationHandler.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosOperationHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosOperationHandler.java
index 8749f81..948fd60 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosOperationHandler.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosOperationHandler.java
@@ -67,22 +67,7 @@ public abstract class KerberosOperationHandler {
   /**
    * Kerberos-env configuration property name: group
    */
-  public final static String KERBEROS_ENV_USER_PRINCIPAL_GROUP = "group";
-
-  /**
-   * Kerberos-env configuration property name: password_chat_timeout
-   */
-  public final static String KERBEROS_ENV_PASSWORD_CHAT_TIMEOUT = "password_chat_timeout";
-
-  /**
-   * Default timeout for password chat
-   */
-  public final static int DEFAULT_PASSWORD_CHAT_TIMEOUT = 5;
-
-  /**
-   * Kerberos-env configuration property name: set_password_expiry
-   */
-  public final static String KERBEROS_ENV_SET_PASSWORD_EXPIRY = "set_password_expiry";
+  public final static String KERBEROS_ENV_USER_PRINCIPAL_GROUP = "ipa_user_group";
 
   /**
    * Kerberos-env configuration property name: ad_create_attributes_template
@@ -232,16 +217,26 @@ public abstract class KerberosOperationHandler {
    * @param defaultRealm            a String declaring the default Kerberos realm (or domain)
    * @param kerberosConfiguration   a Map of key/value pairs containing data from the kerberos-env configuration set
    */
-  public abstract void open(PrincipalKeyCredential administratorCredential, String defaultRealm, Map<String, String> kerberosConfiguration)
-      throws KerberosOperationException;
+  public void open(PrincipalKeyCredential administratorCredential, String defaultRealm, Map<String, String> kerberosConfiguration)
+      throws KerberosOperationException {
+
+    setAdministratorCredential(administratorCredential);
+    setDefaultRealm(defaultRealm);
+
+    if (kerberosConfiguration != null) {
+      setKeyEncryptionTypes(translateEncryptionTypes(kerberosConfiguration.get(KERBEROS_ENV_ENCRYPTION_TYPES), "\\s+"));
+      setExecutableSearchPaths(kerberosConfiguration.get(KERBEROS_ENV_EXECUTABLE_SEARCH_PATHS));
+    }
+  }
 
   /**
    * Closes and cleans up any resources used by this KerberosOperationHandler
    * <p/>
    * It is expected that this KerberosOperationHandler will not be used after this call.
    */
-  public abstract void close()
-      throws KerberosOperationException;
+  public void close() throws KerberosOperationException {
+    setOpen(false);
+  }
 
   /**
    * Test to see if the specified principal exists in a previously configured KDC
@@ -249,10 +244,11 @@ public abstract class KerberosOperationHandler {
    * The implementation is specific to a particular type of KDC.
    *
    * @param principal a String containing the principal to test
+   * @param service   a boolean value indicating whether the principal is for a service or not
    * @return true if the principal exists; false otherwise
    * @throws KerberosOperationException
    */
-  public abstract boolean principalExists(String principal)
+  public abstract boolean principalExists(String principal, boolean service)
       throws KerberosOperationException;
 
   /**
@@ -277,11 +273,12 @@ public abstract class KerberosOperationHandler {
    *
    * @param principal a String containing the principal to update
    * @param password  a String containing the password to set
+   * @param service   a boolean value indicating whether the principal is for a service or not
    * @return an Integer declaring the new key number
    * @throws KerberosOperationException
    * @throws KerberosPrincipalDoesNotExistException if the principal does not exist
    */
-  public abstract Integer setPrincipalPassword(String principal, String password)
+  public abstract Integer setPrincipalPassword(String principal, String password, boolean service)
       throws KerberosOperationException;
 
   /**
@@ -290,10 +287,11 @@ public abstract class KerberosOperationHandler {
    * The implementation is specific to a particular type of KDC.
    *
    * @param principal a String containing the principal to remove
+   * @param service   a boolean value indicating whether the principal is for a service or not
    * @return true if the principal was successfully removed; otherwise false
    * @throws KerberosOperationException
    */
-  public abstract boolean removePrincipal(String principal)
+  public abstract boolean removePrincipal(String principal, boolean service)
       throws KerberosOperationException;
 
   /**
@@ -313,7 +311,7 @@ public abstract class KerberosOperationHandler {
     if (credential == null) {
       throw new KerberosOperationException("Missing KDC administrator credential");
     } else {
-      return principalExists(credential.getPrincipal());
+      return principalExists(credential.getPrincipal(), false);
     }
   }
 
@@ -568,11 +566,11 @@ public abstract class KerberosOperationHandler {
    * @param keyEncryptionTypes a Set of EncryptionKey values or null to indicate the default set
    */
   public void setKeyEncryptionTypes(Set<EncryptionType> keyEncryptionTypes) {
-    this.keyEncryptionTypes = new HashSet<>(
-      (keyEncryptionTypes == null)
-        ? DEFAULT_CIPHERS
-        : keyEncryptionTypes
-    );
+    this.keyEncryptionTypes = Collections.unmodifiableSet(new HashSet<>(
+        (keyEncryptionTypes == null)
+            ? DEFAULT_CIPHERS
+            : keyEncryptionTypes
+    ));
   }
 
 
@@ -713,8 +711,8 @@ public abstract class KerberosOperationHandler {
    * <p/>
    * See {@link org.apache.ambari.server.utils.ShellCommandUtil#runCommand(String[], Map<String,String>)}
    *
-   * @param command an array of String value representing the command and its arguments
-   * @param envp a map of string, string of environment variables
+   * @param command            an array of String value representing the command and its arguments
+   * @param envp               a map of string, string of environment variables
    * @param interactiveHandler a handler to provide responses to queries from the command,
    *                           or null if no queries are expected
    * @return a ShellCommandUtil.Result declaring the result of the operation
@@ -751,7 +749,7 @@ public abstract class KerberosOperationHandler {
    * @see #executeCommand(String[], Map, ShellCommandUtil.InteractiveHandler)
    */
   protected ShellCommandUtil.Result executeCommand(String[] command)
-          throws KerberosOperationException {
+      throws KerberosOperationException {
     return executeCommand(command, null);
   }
 
@@ -760,7 +758,7 @@ public abstract class KerberosOperationHandler {
    * <p/>
    * See {@link org.apache.ambari.server.utils.ShellCommandUtil#runCommand(String[])}
    *
-   * @param command an array of String value representing the command and its arguments
+   * @param command            an array of String value representing the command and its arguments
    * @param interactiveHandler a handler to provide responses to queries from the command,
    *                           or null if no queries are expected
    * @return a ShellCommandUtil.Result declaring the result of the operation

http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java
index 1b0f4fb..ff5f5ce 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java
@@ -22,14 +22,18 @@ import static org.apache.ambari.server.serveraction.kerberos.KerberosIdentityDat
 
 import java.io.File;
 import java.io.IOException;
+import java.lang.reflect.Type;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Set;
 
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.actionmanager.HostRoleStatus;
 import org.apache.ambari.server.agent.CommandReport;
 import org.apache.ambari.server.agent.ExecutionCommand;
 import org.apache.ambari.server.controller.KerberosHelper;
+import org.apache.ambari.server.orm.dao.HostDAO;
+import org.apache.ambari.server.orm.entities.HostEntity;
 import org.apache.ambari.server.security.credential.PrincipalKeyCredential;
 import org.apache.ambari.server.serveraction.AbstractServerAction;
 import org.apache.ambari.server.state.Cluster;
@@ -40,6 +44,7 @@ import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.reflect.TypeToken;
 import com.google.inject.Inject;
 
 /**
@@ -171,6 +176,8 @@ public abstract class KerberosServerAction extends AbstractServerAction {
   @Inject
   private KerberosHelper kerberosHelper;
 
+  @Inject
+  HostDAO hostDAO;
   /**
    * Given a (command parameter) Map and a property name, attempts to safely retrieve the requested
    * data.
@@ -543,21 +550,8 @@ public abstract class KerberosServerAction extends AbstractServerAction {
 
     if (record != null) {
       String principal = record.get(KerberosIdentityDataFileReader.PRINCIPAL);
-
       if (principal != null) {
-        String hostname = record.get(KerberosIdentityDataFileReader.HOSTNAME);
-
-        if(KerberosHelper.AMBARI_SERVER_HOST_NAME.equals(hostname)) {
-          // Replace KerberosHelper.AMBARI_SERVER_HOST_NAME with the actual hostname where the Ambari
-          // server is... this host
-          hostname = StageUtils.getHostName();
-        }
-
-        // Evaluate the principal "pattern" found in the record to generate the "evaluated principal"
-        // by replacing the _HOST and _REALM variables.
-        String evaluatedPrincipal = principal.replace("_HOST", hostname).replace("_REALM", defaultRealm);
-
-        commandReport = processIdentity(record, evaluatedPrincipal, operationHandler, kerberosConfiguration, requestSharedDataContext);
+        commandReport = processIdentity(record, principal, operationHandler, kerberosConfiguration, requestSharedDataContext);
       }
     }
 
@@ -588,6 +582,32 @@ public abstract class KerberosServerAction extends AbstractServerAction {
     }
   }
 
+
+  protected Set<String> getHostFilter() {
+    String serializedValue = getCommandParameterValue(HOST_FILTER);
+
+    if (serializedValue != null) {
+      Type type = new TypeToken<Set<String>>() {
+      }.getType();
+      return StageUtils.getGson().fromJson(serializedValue, type);
+    } else {
+      return null;
+    }
+  }
+
+  protected boolean hasHostFilters() {
+    Set<String> hostFilers = getHostFilter();
+    return hostFilers != null && hostFilers.size() > 0;
+  }
+
+  protected Long ambariServerHostID(){
+    String ambariServerHostName = StageUtils.getHostName();
+    HostEntity ambariServerHostEntity = hostDAO.findByName(ambariServerHostName);
+    return (ambariServerHostEntity == null)
+        ? null
+        : ambariServerHostEntity.getHostId();
+  }
+
   /**
    * A Kerberos operation type
    * <ul>