You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by nc...@apache.org on 2017/11/13 16:57:19 UTC

[02/51] [abbrv] ambari git commit: AMBARI-22293. Improve KDC integration (rlevas)

http://git-wip-us.apache.org/repos/asf/ambari/blob/f844e5f3/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/MITKerberosOperationHandler.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/MITKerberosOperationHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/MITKerberosOperationHandler.java
index 0997f65..bbcd6e8 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/MITKerberosOperationHandler.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/MITKerberosOperationHandler.java
@@ -18,21 +18,17 @@
 
 package org.apache.ambari.server.serveraction.kerberos;
 
-import java.text.NumberFormat;
-import java.text.ParseException;
 import java.util.ArrayList;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
-import java.util.Queue;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import java.util.Set;
 
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.security.credential.PrincipalKeyCredential;
 import org.apache.ambari.server.utils.ShellCommandUtil;
-import org.apache.commons.lang.ArrayUtils;
+import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang.StringUtils;
+import org.apache.directory.shared.kerberos.codec.types.EncryptionType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -45,37 +41,24 @@ import com.google.inject.Inject;
  * It is assumed that a MIT Kerberos client is installed and that the kdamin shell command is
  * available
  */
-public class MITKerberosOperationHandler extends KerberosOperationHandler {
+public class MITKerberosOperationHandler extends KDCKerberosOperationHandler {
+
+  private final static Logger LOG = LoggerFactory.getLogger(MITKerberosOperationHandler.class);
 
   @Inject
   private Configuration configuration;
 
   /**
-   * A regular expression pattern to use to parse the key number from the text captured from the
-   * get_principal kadmin command
-   */
-  private final static Pattern PATTERN_GET_KEY_NUMBER = Pattern.compile("^.*?Key: vno (\\d+).*$", Pattern.DOTALL);
-
-  private final static Logger LOG = LoggerFactory.getLogger(MITKerberosOperationHandler.class);
-
-  /**
    * A String containing user-specified attributes used when creating principals
    */
   private String createAttributes = null;
 
-  private String adminServerHost = null;
-
   /**
    * A String containing the resolved path to the kdamin executable
    */
   private String executableKadmin = null;
 
   /**
-   * A String containing the resolved path to the kdamin.local executable
-   */
-  private String executableKadminLocal = null;
-
-  /**
    * Prepares and creates resources to be used by this KerberosOperationHandler
    * <p/>
    * It is expected that this KerberosOperationHandler will not be used before this call.
@@ -92,39 +75,25 @@ public class MITKerberosOperationHandler extends KerberosOperationHandler {
    * @throws KerberosOperationException           if an unexpected error occurred
    */
   @Override
-  public void open(PrincipalKeyCredential administratorCredentials, String realm,
-                   Map<String, String> kerberosConfiguration)
+  public void open(PrincipalKeyCredential administratorCredentials, String realm, Map<String, String> kerberosConfiguration)
       throws KerberosOperationException {
 
-    setAdministratorCredential(administratorCredentials);
-    setDefaultRealm(realm);
-
     if (kerberosConfiguration != null) {
-      setKeyEncryptionTypes(translateEncryptionTypes(kerberosConfiguration.get(KERBEROS_ENV_ENCRYPTION_TYPES), "\\s+"));
-      setAdminServerHost(kerberosConfiguration.get(KERBEROS_ENV_ADMIN_SERVER_HOST));
-      setExecutableSearchPaths(kerberosConfiguration.get(KERBEROS_ENV_EXECUTABLE_SEARCH_PATHS));
-      setCreateAttributes(kerberosConfiguration.get(KERBEROS_ENV_KDC_CREATE_ATTRIBUTES));
-    } else {
-      setKeyEncryptionTypes(null);
-      setAdminServerHost(null);
-      setExecutableSearchPaths((String) null);
-      setCreateAttributes(null);
+      createAttributes = kerberosConfiguration.get(KERBEROS_ENV_KDC_CREATE_ATTRIBUTES);
     }
 
     // Pre-determine the paths to relevant Kerberos executables
     executableKadmin = getExecutable("kadmin");
-    executableKadminLocal = getExecutable("kadmin.local");
 
-    setOpen(true);
+    super.open(administratorCredentials, realm, kerberosConfiguration);
   }
 
   @Override
   public void close() throws KerberosOperationException {
-    // There is nothing to do here.
-    setOpen(false);
-
+    createAttributes = null;
     executableKadmin = null;
-    executableKadminLocal = null;
+
+    super.close();
   }
 
   /**
@@ -134,6 +103,7 @@ public class MITKerberosOperationHandler 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 KerberosKDCConnectionException       if a connection to the KDC cannot be made
    * @throws KerberosAdminAuthenticationException if the administrator credentials fail to authenticate
@@ -141,26 +111,25 @@ public class MITKerberosOperationHandler extends KerberosOperationHandler {
    * @throws KerberosOperationException           if an unexpected error occurred
    */
   @Override
-  public boolean principalExists(String principal)
+  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 (!StringUtils.isEmpty(principal)) {
       // Create the KAdmin query to execute:
-      ShellCommandUtil.Result result = invokeKAdmin(String.format("get_principal %s", principal), null);
+      ShellCommandUtil.Result result = invokeKAdmin(String.format("get_principal %s", principal));
 
       // If there is data from STDOUT, see if the following string exists:
       //    Principal: <principal>
       String stdOut = result.getStdout();
       return (stdOut != null) && stdOut.contains(String.format("Principal: %s", principal));
     }
-  }
 
+    return false;
+  }
 
   /**
    * Creates a new principal in a previously configured MIT KDC
@@ -188,72 +157,25 @@ public class MITKerberosOperationHandler extends KerberosOperationHandler {
 
     if (StringUtils.isEmpty(principal)) {
       throw new KerberosOperationException("Failed to create new principal - no principal specified");
-    } else if (StringUtils.isEmpty(password)) {
-      throw new KerberosOperationException("Failed to create new principal - no password specified");
-    } else {
-      String createAttributes = getCreateAttributes();
-      // Create the kdamin query:  add_principal <-randkey|-pw <password>> [<options>] <principal>
-      ShellCommandUtil.Result result = invokeKAdmin(String.format("add_principal %s %s",
-          (createAttributes == null) ? "" : createAttributes, principal), password);
-
-      // If there is data from STDOUT, see if the following string exists:
-      //    Principal "<principal>" created
-      String stdOut = result.getStdout();
-      String stdErr = result.getStderr();
-      if ((stdOut != null) && stdOut.contains(String.format("Principal \"%s\" created", principal))) {
-        return getKeyNumber(principal);
-      } else if ((stdErr != null) && stdErr.contains(String.format("Principal or policy already exists while creating \"%s\"", principal))) {
-        throw new KerberosPrincipalAlreadyExistsException(principal);
-      } else {
-        LOG.error("Failed to execute kadmin query: add_principal -pw \"********\" {} {}\nSTDOUT: {}\nSTDERR: {}",
-            (createAttributes == null) ? "" : createAttributes, principal, stdOut, result.getStderr());
-        throw new KerberosOperationException(String.format("Failed to create service principal for %s\nSTDOUT: %s\nSTDERR: %s",
-            principal, stdOut, result.getStderr()));
-      }
-    }
-  }
-
-  /**
-   * Updates the password for an existing principal in a previously configured MIT KDC
-   * <p/>
-   * This implementation creates a query to send to the kadmin 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 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 KerberosPrincipalDoesNotExistException if the principal does not exist
-   * @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");
     }
 
-    if (StringUtils.isEmpty(principal)) {
-      throw new KerberosOperationException("Failed to set password - no principal specified");
-    } else if (StringUtils.isEmpty(password)) {
-      throw new KerberosOperationException("Failed to set password - no password specified");
+    // Create the kdamin query:  add_principal <-randkey|-pw <password>> [<options>] <principal>
+    ShellCommandUtil.Result result = invokeKAdmin(String.format("add_principal -randkey %s %s",
+        (createAttributes == null) ? "" : createAttributes, principal));
+
+    // If there is data from STDOUT, see if the following string exists:
+    //    Principal "<principal>" created
+    String stdOut = result.getStdout();
+    String stdErr = result.getStderr();
+    if ((stdOut != null) && stdOut.contains(String.format("Principal \"%s\" created", principal))) {
+      return 0;
+    } else if ((stdErr != null) && stdErr.contains(String.format("Principal or policy already exists while creating \"%s\"", principal))) {
+      throw new KerberosPrincipalAlreadyExistsException(principal);
     } else {
-      // Create the kdamin query:  change_password <-randkey|-pw <password>> <principal>
-      ShellCommandUtil.Result result = invokeKAdmin(String.format("change_password %s", principal), password);
-
-      String stdOut = result.getStdout();
-      String stdErr = result.getStderr();
-      if ((stdOut != null) && stdOut.contains(String.format("Password for \"%s\" changed", principal))) {
-        return getKeyNumber(principal);
-      } else if ((stdErr != null) && stdErr.contains("Principal does not exist")) {
-        throw new KerberosPrincipalDoesNotExistException(principal);
-      } else {
-        LOG.error("Failed to execute kadmin query: change_password -pw \"********\" {} \nSTDOUT: {}\nSTDERR: {}",
-            principal, stdOut, result.getStderr());
-        throw new KerberosOperationException(String.format("Failed to update password for %s\nSTDOUT: %s\nSTDERR: %s",
-            principal, stdOut, result.getStderr()));
-      }
+      LOG.error("Failed to execute kadmin query: add_principal -pw \"********\" {} {}\nSTDOUT: {}\nSTDERR: {}",
+          (createAttributes == null) ? "" : createAttributes, principal, stdOut, result.getStderr());
+      throw new KerberosOperationException(String.format("Failed to create service principal for %s\nSTDOUT: %s\nSTDERR: %s",
+          principal, stdOut, result.getStderr()));
     }
   }
 
@@ -263,6 +185,7 @@ public class MITKerberosOperationHandler 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
@@ -270,181 +193,63 @@ public class MITKerberosOperationHandler 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 (StringUtils.isEmpty(principal)) {
-      throw new KerberosOperationException("Failed to remove new principal - no principal specified");
-    } else {
-      ShellCommandUtil.Result result = invokeKAdmin(String.format("delete_principal -force %s", principal), null);
-
-      // If there is data from STDOUT, see if the following string exists:
-      //    Principal "<principal>" created
-      String stdOut = result.getStdout();
-      return (stdOut != null) && !stdOut.contains("Principal does not exist");
+      throw new KerberosOperationException("Failed to remove principal - no principal specified");
     }
-  }
 
-  /**
-   * Sets the KDC administrator server host address
-   *
-   * @param adminServerHost the ip address or FQDN of the KDC administrator server
-   */
-  public void setAdminServerHost(String adminServerHost) {
-    this.adminServerHost = adminServerHost;
-  }
+    ShellCommandUtil.Result result = invokeKAdmin(String.format("delete_principal -force %s", principal));
 
-  /**
-   * Gets the IP address or FQDN of the KDC administrator server
-   *
-   * @return the IP address or FQDN of the KDC administrator server
-   */
-  public String getAdminServerHost() {
-    return this.adminServerHost;
-  }
-
-  /**
-   * Sets the (additional) principal creation attributes
-   *
-   * @param createAttributes the additional principal creations attributes
-   */
-  public void setCreateAttributes(String createAttributes) {
-    this.createAttributes = createAttributes;
-  }
-
-  /**
-   * Gets the (additional) principal creation attributes
-   *
-   * @return the additional principal creations attributes or null
-   */
-  public String getCreateAttributes() {
-    return createAttributes;
-  }
-
-  /**
-   * 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 (StringUtils.isEmpty(principal)) {
-      throw new KerberosOperationException("Failed to get key number for principal  - no principal specified");
-    } else {
-      // Create the kdamin query:  get_principal <principal>
-      ShellCommandUtil.Result result = invokeKAdmin(String.format("get_principal %s", principal), null);
-
-      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);
-      }
-    }
+    // If there is data from STDOUT, see if the following string exists:
+    //    Principal "<principal>" created
+    String stdOut = result.getStdout();
+    return (stdOut != null) && !stdOut.contains("Principal does not exist");
   }
 
   /**
    * Invokes the kadmin shell command to issue queries
    *
-   * @param query        a String containing the query to send to the kdamin command
-   * @param userPassword a String containing the user's password to set or update if necessary,
-   *                     null if not needed
+   * @param query a String containing the query to send to the kdamin command
    * @return a ShellCommandUtil.Result containing the result of the operation
    * @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
    */
-  protected ShellCommandUtil.Result invokeKAdmin(String query, String userPassword)
+  protected ShellCommandUtil.Result invokeKAdmin(String query)
       throws KerberosOperationException {
     if (StringUtils.isEmpty(query)) {
       throw new KerberosOperationException("Missing kadmin query");
     }
 
-    ShellCommandUtil.Result result = null;
-    PrincipalKeyCredential administratorCredential = getAdministratorCredential();
-    String defaultRealm = getDefaultRealm();
+    if (StringUtils.isEmpty(executableKadmin)) {
+      throw new KerberosOperationException("No path for kadmin is available - this KerberosOperationHandler may not have been opened.");
+    }
 
     List<String> command = new ArrayList<>();
+    command.add(executableKadmin);
 
-    String adminPrincipal = (administratorCredential == null)
-        ? null
-        : administratorCredential.getPrincipal();
-
-    ShellCommandUtil.InteractiveHandler interactiveHandler = null;
-
-    if (StringUtils.isEmpty(adminPrincipal)) {
-      // Set the kdamin interface to be kadmin.local
-      if (StringUtils.isEmpty(executableKadminLocal)) {
-        throw new KerberosOperationException("No path for kadmin.local is available - this KerberosOperationHandler may not have been opened.");
-      }
-
-      command.add(executableKadminLocal);
-
-      if (userPassword != null) {
-        interactiveHandler = new InteractivePasswordHandler(null, userPassword);
-      }
-    } else {
-      if (StringUtils.isEmpty(executableKadmin)) {
-        throw new KerberosOperationException("No path for kadmin is available - this KerberosOperationHandler may not have been opened.");
-      }
-      char[] adminPassword = administratorCredential.getKey();
-
-      // Set the kdamin interface to be kadmin
-      command.add(executableKadmin);
-
-      // Add explicit KDC admin host, if available
-      if (!StringUtils.isEmpty(getAdminServerHost())) {
-        command.add("-s");
-        command.add(getAdminServerHost());
-      }
-
-      // Add the administrative principal
-      command.add("-p");
-      command.add(adminPrincipal);
+    // Add the credential cache, if available
+    String credentialCacheFilePath = getCredentialCacheFilePath();
+    if (!StringUtils.isEmpty(credentialCacheFilePath)) {
+      command.add("-c");
+      command.add(credentialCacheFilePath);
+    }
 
-      if (!ArrayUtils.isEmpty(adminPassword)) {
-        interactiveHandler = new InteractivePasswordHandler(String.valueOf(adminPassword), userPassword);
-      } else if (userPassword != null) {
-        interactiveHandler = new InteractivePasswordHandler(null, userPassword);
-      }
+    // Add explicit KDC admin host, if available
+    String adminSeverHost = getAdminServerHost();
+    if (!StringUtils.isEmpty(adminSeverHost)) {
+      command.add("-s");
+      command.add(adminSeverHost);
     }
 
+    // Add default realm clause, if available
+    String defaultRealm = getDefaultRealm();
     if (!StringUtils.isEmpty(defaultRealm)) {
-      // Add default realm clause
       command.add("-r");
       command.add(defaultRealm);
     }
@@ -457,12 +262,13 @@ public class MITKerberosOperationHandler extends KerberosOperationHandler {
       LOG.debug("Executing: {}", command);
     }
 
+    ShellCommandUtil.Result result = null;
     int retryCount = configuration.getKerberosOperationRetries();
     int tries = 0;
 
     while (tries <= retryCount) {
       try {
-        result = executeCommand(command.toArray(new String[command.size()]), null, interactiveHandler);
+        result = executeCommand(command.toArray(new String[command.size()]));
       } catch (KerberosOperationException exception) {
         if (tries == retryCount) {
           throw exception;
@@ -486,13 +292,16 @@ public class MITKerberosOperationHandler extends KerberosOperationHandler {
     }
 
 
-    if (!result.isSuccessful()) {
+    if ((result == null) || !result.isSuccessful()) {
+      int exitCode = (result == null) ? -999 : result.getExitCode();
+      String stdOut = (result == null) ? "" : result.getStdout();
+      String stdErr = (result == null) ? "" : result.getStderr();
+
       String message = String.format("Failed to execute kadmin:\n\tCommand: %s\n\tExitCode: %s\n\tSTDOUT: %s\n\tSTDERR: %s",
-          command, result.getExitCode(), result.getStdout(), result.getStderr());
+          command, exitCode, stdOut, stdErr);
       LOG.warn(message);
 
       // Test STDERR to see of any "expected" error conditions were encountered...
-      String stdErr = result.getStderr();
       // Did admin credentials fail?
       if (stdErr.contains("Client not found in Kerberos database")) {
         throw new KerberosAdminAuthenticationException(stdErr);
@@ -513,57 +322,56 @@ public class MITKerberosOperationHandler extends KerberosOperationHandler {
       } else {
         throw new KerberosOperationException(String.format("Unexpected error condition executing the kadmin command. STDERR: %s", stdErr));
       }
+    } else {
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("Executed the following command:\n{}\nSTDOUT: {}\nSTDERR: {}",
+            StringUtils.join(command, " "), result.getStdout(), result.getStderr());
+      }
     }
 
     return result;
   }
 
-  /**
-   * InteractivePasswordHandler is a {@link org.apache.ambari.server.utils.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)
-     */
-    public InteractivePasswordHandler(String adminPassword, String userPassword) {
-      responses = new LinkedList<>();
-
-      if (adminPassword != null) {
-        responses.offer(adminPassword);
-      }
+  @Override
+  protected String[] getKinitCommand(String executableKinit, PrincipalKeyCredential credentials, String credentialsCache) {
+    // kinit -c <path> -S kadmin/`hostname -f` <principal>
+    return new String[]{
+        executableKinit,
+        "-c",
+        credentialsCache,
+        "-S",
+        String.format("kadmin/%s", getAdminServerHost()),
+        credentials.getPrincipal()
+    };
+  }
 
-      if (userPassword != null) {
-        responses.offer(userPassword);
-        responses.offer(userPassword);  // Add a 2nd time for the password "confirmation" request
+  @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(',');
+        }
+        encryptionTypeSpecBuilder.append(encryptionType.getName());
+        encryptionTypeSpecBuilder.append(":normal");
       }
 
-      currentResponses = new LinkedList<>(responses);
+      encryptionTypeSpec = encryptionTypeSpecBuilder.toString();
     }
 
-    @Override
-    public boolean done() {
-      return currentResponses.size() == 0;
-    }
+    String query = (StringUtils.isEmpty(encryptionTypeSpec))
+        ? String.format("xst -k \"%s\" %s", keytabFileDestinationPath, principal)
+        : String.format("xst -k \"%s\" -e %s %s", keytabFileDestinationPath, encryptionTypeSpec, principal);
 
-    @Override
-    public String getResponse(String query) {
-      return currentResponses.poll();
-    }
+    ShellCommandUtil.Result result = invokeKAdmin(query);
 
-    @Override
-    public void start() {
-      currentResponses = new LinkedList<>(responses);
+    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);
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f844e5f3/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog300.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog300.java b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog300.java
index bfe2a13..d3e924e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog300.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog300.java
@@ -45,6 +45,7 @@ import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.Config;
 import org.apache.ambari.server.state.ConfigHelper;
+import org.apache.commons.collections.MapUtils;
 import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -149,6 +150,7 @@ public class UpgradeCatalog300 extends AbstractUpgradeCatalog {
     showHcatDeletedUserMessage();
     setStatusOfStagesAndRequests();
     updateLogSearchConfigs();
+    updateKerberosConfigurations();
   }
 
   protected void showHcatDeletedUserMessage() {
@@ -265,7 +267,7 @@ public class UpgradeCatalog300 extends AbstractUpgradeCatalog {
                 "logsearch-common-properties", Collections.emptyMap(), "ambari-upgrade",
                 String.format("Updated logsearch-common-properties during Ambari Upgrade from %s to %s",
                     getSourceVersion(), getTargetVersion()));
-            
+
             String defaultLogLevels = logSearchProperties.getProperties().get("logsearch.logfeeder.include.default.level");
 
             Set<String> removeProperties = Sets.newHashSet("logsearch.logfeeder.include.default.level");
@@ -324,7 +326,7 @@ public class UpgradeCatalog300 extends AbstractUpgradeCatalog {
               updateConfigurationPropertiesForCluster(cluster, "logsearch-audit_logs-solrconfig", Collections.singletonMap("content", content), true, true);
             }
           }
-          
+
           Config logFeederOutputConfig = cluster.getDesiredConfigByType("logfeeder-output-config");
           if (logFeederOutputConfig != null) {
             String content = logFeederOutputConfig.getProperties().get("content");
@@ -346,4 +348,28 @@ public class UpgradeCatalog300 extends AbstractUpgradeCatalog {
       }
     }
   }
+
+  protected void updateKerberosConfigurations() throws AmbariException {
+    AmbariManagementController ambariManagementController = injector.getInstance(AmbariManagementController.class);
+    Clusters clusters = ambariManagementController.getClusters();
+    if (clusters != null) {
+      Map<String, Cluster> clusterMap = clusters.getClusters();
+
+      if (!MapUtils.isEmpty(clusterMap)) {
+        for (Cluster cluster : clusterMap.values()) {
+          Config config = cluster.getDesiredConfigByType("kerberos-env");
+
+          if (config != null) {
+            Map<String, String> properties = config.getProperties();
+            if (properties.containsKey("group")) {
+              // Covert kerberos-env/group to kerberos-env/ipa_user_group
+              updateConfigurationPropertiesForCluster(cluster, "kerberos-env",
+                  Collections.singletonMap("ipa_user_group", properties.get("group")), Collections.singleton("group"),
+                  true, false);
+            }
+          }
+        }
+      }
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f844e5f3/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/configuration/kerberos-env.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/configuration/kerberos-env.xml b/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/configuration/kerberos-env.xml
index 0a08121..293bcf8 100644
--- a/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/configuration/kerberos-env.xml
+++ b/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/configuration/kerberos-env.xml
@@ -349,8 +349,8 @@
     <on-ambari-upgrade add="true"/>
   </property>
   <property>
-    <name>group</name>
-    <display-name>IPA Group</display-name>
+    <name>ipa_user_group</name>
+    <display-name>IPA User Group</display-name>
     <description>
       The group in IPA user principals should be member of
     </description>
@@ -362,38 +362,6 @@
     <on-ambari-upgrade add="true"/>
   </property>
   <property>
-    <name>set_password_expiry</name>
-    <display-name>Set IPA principal password expiry</display-name>
-    <description>
-      Indicates whether Ambari should set the password expiry for the principals it creates. By default
-      IPA does not allow this. It requires write permission of the admin principal to the krbPasswordExpiry
-      attribute. If set IPA principal password expiry is not true it is assumed that a suitable password
-      policy is in place for the IPA Group principals are added to.
-    </description>
-    <value>false</value>
-    <value-attributes>
-      <type>boolean</type>
-      <overridable>false</overridable>
-      <visible>false</visible>
-    </value-attributes>
-    <on-ambari-upgrade add="true"/>
-  </property>
-  <property>
-    <name>password_chat_timeout</name>
-    <display-name>Set IPA kinit password chat timeout</display-name>
-    <description>
-      Indicates the timeout in seconds that Ambari should wait for a response during a password chat. This is
-      because it can take some time due to lookups before a response is there.
-    </description>
-    <value>5</value>
-    <value-attributes>
-      <visible>false</visible>
-      <type>int</type>
-      <overridable>false</overridable>
-    </value-attributes>
-    <on-ambari-upgrade add="true"/>
-  </property>
-  <property>
     <name>preconfigure_services</name>
     <display-name>Pre-configure services</display-name>
     <description>

http://git-wip-us.apache.org/repos/asf/ambari/blob/f844e5f3/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-30/configuration/kerberos-env.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-30/configuration/kerberos-env.xml b/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-30/configuration/kerberos-env.xml
index 0a08121..293bcf8 100644
--- a/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-30/configuration/kerberos-env.xml
+++ b/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-30/configuration/kerberos-env.xml
@@ -349,8 +349,8 @@
     <on-ambari-upgrade add="true"/>
   </property>
   <property>
-    <name>group</name>
-    <display-name>IPA Group</display-name>
+    <name>ipa_user_group</name>
+    <display-name>IPA User Group</display-name>
     <description>
       The group in IPA user principals should be member of
     </description>
@@ -362,38 +362,6 @@
     <on-ambari-upgrade add="true"/>
   </property>
   <property>
-    <name>set_password_expiry</name>
-    <display-name>Set IPA principal password expiry</display-name>
-    <description>
-      Indicates whether Ambari should set the password expiry for the principals it creates. By default
-      IPA does not allow this. It requires write permission of the admin principal to the krbPasswordExpiry
-      attribute. If set IPA principal password expiry is not true it is assumed that a suitable password
-      policy is in place for the IPA Group principals are added to.
-    </description>
-    <value>false</value>
-    <value-attributes>
-      <type>boolean</type>
-      <overridable>false</overridable>
-      <visible>false</visible>
-    </value-attributes>
-    <on-ambari-upgrade add="true"/>
-  </property>
-  <property>
-    <name>password_chat_timeout</name>
-    <display-name>Set IPA kinit password chat timeout</display-name>
-    <description>
-      Indicates the timeout in seconds that Ambari should wait for a response during a password chat. This is
-      because it can take some time due to lookups before a response is there.
-    </description>
-    <value>5</value>
-    <value-attributes>
-      <visible>false</visible>
-      <type>int</type>
-      <overridable>false</overridable>
-    </value-attributes>
-    <on-ambari-upgrade add="true"/>
-  </property>
-  <property>
     <name>preconfigure_services</name>
     <display-name>Pre-configure services</display-name>
     <description>

http://git-wip-us.apache.org/repos/asf/ambari/blob/f844e5f3/ambari-server/src/main/resources/stacks/PERF/1.0/services/KERBEROS/configuration/kerberos-env.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/PERF/1.0/services/KERBEROS/configuration/kerberos-env.xml b/ambari-server/src/main/resources/stacks/PERF/1.0/services/KERBEROS/configuration/kerberos-env.xml
index 66e81db..a66a7a6 100644
--- a/ambari-server/src/main/resources/stacks/PERF/1.0/services/KERBEROS/configuration/kerberos-env.xml
+++ b/ambari-server/src/main/resources/stacks/PERF/1.0/services/KERBEROS/configuration/kerberos-env.xml
@@ -348,8 +348,8 @@
     <on-ambari-upgrade add="true"/>
   </property>
   <property>
-    <name>group</name>
-    <display-name>IPA Group</display-name>
+    <name>ipa_user_group</name>
+    <display-name>IPA User Group</display-name>
     <description>
       The group in IPA user principals should be member of
     </description>
@@ -360,36 +360,4 @@
     </value-attributes>
     <on-ambari-upgrade add="true"/>
   </property>
-  <property>
-    <name>set_password_expiry</name>
-    <display-name>Set IPA principal password expiry</display-name>
-    <description>
-      Indicates whether Ambari should set the password expiry for the principals it creates. By default
-      IPA does not allow this. It requires write permission of the admin principal to the krbPasswordExpiry
-      attribute. If set IPA principal password expiry is not true it is assumed that a suitable password
-      policy is in place for the IPA Group principals are added to.
-    </description>
-    <value>false</value>
-    <value-attributes>
-      <type>boolean</type>
-      <overridable>false</overridable>
-      <visible>false</visible>
-    </value-attributes>
-    <on-ambari-upgrade add="true"/>
-  </property>
-  <property>
-    <name>password_chat_timeout</name>
-    <display-name>Set IPA kinit password chat timeout</display-name>
-    <description>
-      Indicates the timeout in seconds that Ambari should wait for a response during a password chat. This is
-      because it can take some time due to lookups before a response is there.
-    </description>
-    <value>5</value>
-    <value-attributes>
-      <visible>false</visible>
-      <type>int</type>
-      <overridable>false</overridable>
-    </value-attributes>
-    <on-ambari-upgrade add="true"/>
-  </property>
 </configuration>

http://git-wip-us.apache.org/repos/asf/ambari/blob/f844e5f3/ambari-server/src/test/java/org/apache/ambari/server/controller/KerberosHelperTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/KerberosHelperTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/KerberosHelperTest.java
index a3074ae..ee87d24 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/KerberosHelperTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/KerberosHelperTest.java
@@ -188,7 +188,7 @@ public class KerberosHelperTest extends EasyMockSupport {
           }
 
           @Override
-          public boolean principalExists(String principal) throws KerberosOperationException {
+          public boolean principalExists(String principal, boolean service) throws KerberosOperationException {
             return "principal".equals(principal);
           }
 
@@ -198,12 +198,12 @@ public class KerberosHelperTest extends EasyMockSupport {
           }
 
           @Override
-          public Integer setPrincipalPassword(String principal, String password) throws KerberosOperationException {
+          public Integer setPrincipalPassword(String principal, String password, boolean service) throws KerberosOperationException {
             return null;
           }
 
           @Override
-          public boolean removePrincipal(String principal) throws KerberosOperationException {
+          public boolean removePrincipal(String principal, boolean service) throws KerberosOperationException {
             return false;
           }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/f844e5f3/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/ADKerberosOperationHandlerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/ADKerberosOperationHandlerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/ADKerberosOperationHandlerTest.java
index 483cc0a..8b3c19a 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/ADKerberosOperationHandlerTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/ADKerberosOperationHandlerTest.java
@@ -19,11 +19,15 @@
 package org.apache.ambari.server.serveraction.kerberos;
 
 import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.anyString;
 import static org.easymock.EasyMock.capture;
 import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.isNull;
 import static org.easymock.EasyMock.newCapture;
 import static org.easymock.EasyMock.replay;
 
+import java.lang.reflect.Method;
 import java.nio.charset.Charset;
 import java.util.HashMap;
 import java.util.List;
@@ -50,6 +54,8 @@ import org.apache.ambari.server.state.stack.OsFamily;
 import org.easymock.Capture;
 import org.easymock.CaptureType;
 import org.easymock.IAnswer;
+import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Ignore;
 import org.junit.Test;
 
@@ -65,6 +71,36 @@ public class ADKerberosOperationHandlerTest extends KerberosOperationHandlerTest
   private static final String DEFAULT_LDAP_URL = "ldaps://10.0.100.4";
   private static final String DEFAULT_PRINCIPAL_CONTAINER_DN = "ou=HDP,DC=HDP01,DC=LOCAL";
   private static final String DEFAULT_REALM = "HDP01.LOCAL";
+  private static final Map<String, String> KERBEROS_ENV_MAP = new HashMap<String, String>() {
+    {
+      put(ADKerberosOperationHandler.KERBEROS_ENV_PRINCIPAL_CONTAINER_DN, DEFAULT_PRINCIPAL_CONTAINER_DN);
+      put(ADKerberosOperationHandler.KERBEROS_ENV_LDAP_URL, DEFAULT_LDAP_URL);
+    }
+  };
+
+  private static Method methodCreateInitialLdapContext;
+
+  private Injector injector;
+  private LdapContext ldapContext;
+
+  @BeforeClass
+  public static void beforeMITKerberosOperationHandlerTest() throws Exception {
+    methodCreateInitialLdapContext = ADKerberosOperationHandler.class.getDeclaredMethod("createInitialLdapContext", Properties.class, Control[].class);
+  }
+
+  @Before
+  public void setup() {
+    injector = Guice.createInjector(new AbstractModule() {
+      @Override
+      protected void configure() {
+        bind(Clusters.class).toInstance(createNiceMock(Clusters.class));
+        bind(Configuration.class).toInstance(createNiceMock(Configuration.class));
+        bind(OsFamily.class).toInstance(createNiceMock(OsFamily.class));
+      }
+    });
+
+    ldapContext = createMock(LdapContext.class);
+  }
 
   @Test(expected = KerberosKDCConnectionException.class)
   public void testOpenExceptionLdapUrlNotProvided() throws Exception {
@@ -95,13 +131,8 @@ public class ADKerberosOperationHandlerTest extends KerberosOperationHandlerTest
   @Test(expected = KerberosAdminAuthenticationException.class)
   public void testOpenExceptionAdminCredentialsNotProvided() throws Exception {
     KerberosOperationHandler handler = new ADKerberosOperationHandler();
-    Map<String, String> kerberosEnvMap = new HashMap<String, String>() {
-      {
-        put(ADKerberosOperationHandler.KERBEROS_ENV_LDAP_URL, DEFAULT_LDAP_URL);
-        put(ADKerberosOperationHandler.KERBEROS_ENV_PRINCIPAL_CONTAINER_DN, DEFAULT_PRINCIPAL_CONTAINER_DN);
-      }
-    };
-    handler.open(null, DEFAULT_REALM, kerberosEnvMap);
+
+    handler.open(null, DEFAULT_REALM, getKerberosEnv());
     handler.close();
   }
 
@@ -124,13 +155,6 @@ public class ADKerberosOperationHandlerTest extends KerberosOperationHandlerTest
     Injector injector = getInjector();
 
     PrincipalKeyCredential kc = new PrincipalKeyCredential(DEFAULT_ADMIN_PRINCIPAL, "wrong");
-    Map<String, String> kerberosEnvMap = new HashMap<String, String>() {
-      {
-        put(ADKerberosOperationHandler.KERBEROS_ENV_LDAP_URL, DEFAULT_LDAP_URL);
-        put(ADKerberosOperationHandler.KERBEROS_ENV_PRINCIPAL_CONTAINER_DN, DEFAULT_PRINCIPAL_CONTAINER_DN);
-      }
-    };
-
     ADKerberosOperationHandler handler = createMockBuilder(ADKerberosOperationHandler.class)
         .addMockedMethod(ADKerberosOperationHandler.class.getDeclaredMethod("createInitialLdapContext", Properties.class, Control[].class))
         .createNiceMock();
@@ -145,7 +169,7 @@ public class ADKerberosOperationHandlerTest extends KerberosOperationHandlerTest
 
     replayAll();
 
-    handler.open(kc, DEFAULT_REALM, kerberosEnvMap);
+    handler.open(kc, DEFAULT_REALM, getKerberosEnv());
     handler.testAdministratorCredentials();
     handler.close();
   }
@@ -155,12 +179,6 @@ public class ADKerberosOperationHandlerTest extends KerberosOperationHandlerTest
     Injector injector = getInjector();
 
     PrincipalKeyCredential kc = new PrincipalKeyCredential("wrong", DEFAULT_ADMIN_PASSWORD);
-    Map<String, String> kerberosEnvMap = new HashMap<String, String>() {
-      {
-        put(ADKerberosOperationHandler.KERBEROS_ENV_LDAP_URL, DEFAULT_LDAP_URL);
-        put(ADKerberosOperationHandler.KERBEROS_ENV_PRINCIPAL_CONTAINER_DN, DEFAULT_PRINCIPAL_CONTAINER_DN);
-      }
-    };
 
     ADKerberosOperationHandler handler = createMockBuilder(ADKerberosOperationHandler.class)
         .addMockedMethod(ADKerberosOperationHandler.class.getDeclaredMethod("createInitialLdapContext", Properties.class, Control[].class))
@@ -176,7 +194,7 @@ public class ADKerberosOperationHandlerTest extends KerberosOperationHandlerTest
 
     replayAll();
 
-    handler.open(kc, DEFAULT_REALM, kerberosEnvMap);
+    handler.open(kc, DEFAULT_REALM, getKerberosEnv());
     handler.testAdministratorCredentials();
     handler.close();
   }
@@ -184,17 +202,8 @@ public class ADKerberosOperationHandlerTest extends KerberosOperationHandlerTest
   @Test(expected = KerberosKDCConnectionException.class)
   public void testTestAdministratorCredentialsKDCConnectionException() throws Exception {
     PrincipalKeyCredential kc = new PrincipalKeyCredential(DEFAULT_ADMIN_PRINCIPAL, DEFAULT_ADMIN_PASSWORD);
-    Map<String, String> kerberosEnvMap = new HashMap<String, String>() {
-      {
-        put(ADKerberosOperationHandler.KERBEROS_ENV_LDAP_URL, "invalid");
-        put(ADKerberosOperationHandler.KERBEROS_ENV_PRINCIPAL_CONTAINER_DN, DEFAULT_PRINCIPAL_CONTAINER_DN);
-      }
-    };
-
-    ADKerberosOperationHandler handler = createMockBuilder(ADKerberosOperationHandler.class)
-        .addMockedMethod(ADKerberosOperationHandler.class.getDeclaredMethod("createInitialLdapContext", Properties.class, Control[].class))
-        .createNiceMock();
 
+    ADKerberosOperationHandler handler = createMockedHandler(methodCreateInitialLdapContext);
     expect(handler.createInitialLdapContext(anyObject(Properties.class), anyObject(Control[].class))).andAnswer(new IAnswer<LdapContext>() {
       @Override
       public LdapContext answer() throws Throwable {
@@ -204,7 +213,7 @@ public class ADKerberosOperationHandlerTest extends KerberosOperationHandlerTest
 
     replayAll();
 
-    handler.open(kc, DEFAULT_REALM, kerberosEnvMap);
+    handler.open(kc, DEFAULT_REALM, getKerberosEnv());
     handler.testAdministratorCredentials();
     handler.close();
   }
@@ -212,21 +221,8 @@ public class ADKerberosOperationHandlerTest extends KerberosOperationHandlerTest
 
   @Test
   public void testTestAdministratorCredentialsSuccess() throws Exception {
-    Injector injector = getInjector();
-
     PrincipalKeyCredential kc = new PrincipalKeyCredential(DEFAULT_ADMIN_PRINCIPAL, DEFAULT_ADMIN_PASSWORD);
-    Map<String, String> kerberosEnvMap = new HashMap<String, String>() {
-      {
-        put(ADKerberosOperationHandler.KERBEROS_ENV_LDAP_URL, DEFAULT_LDAP_URL);
-        put(ADKerberosOperationHandler.KERBEROS_ENV_PRINCIPAL_CONTAINER_DN, DEFAULT_PRINCIPAL_CONTAINER_DN);
-      }
-    };
-
-    ADKerberosOperationHandler handler = createMockBuilder(ADKerberosOperationHandler.class)
-        .addMockedMethod(ADKerberosOperationHandler.class.getDeclaredMethod("createInitialLdapContext", Properties.class, Control[].class))
-        .addMockedMethod(ADKerberosOperationHandler.class.getDeclaredMethod("createSearchControls"))
-        .createNiceMock();
-    injector.injectMembers(handler);
+    ADKerberosOperationHandler handler = createMockedHandler(methodCreateInitialLdapContext);
 
     expect(handler.createInitialLdapContext(anyObject(Properties.class), anyObject(Control[].class)))
         .andAnswer(new IAnswer<LdapContext>() {
@@ -245,23 +241,14 @@ public class ADKerberosOperationHandlerTest extends KerberosOperationHandlerTest
                   }
                 })
                 .once();
-            replay(ldapContext);
             return ldapContext;
           }
         })
         .once();
-    expect(handler.createSearchControls()).andAnswer(new IAnswer<SearchControls>() {
-      @Override
-      public SearchControls answer() throws Throwable {
-        SearchControls searchControls = createNiceMock(SearchControls.class);
-        replay(searchControls);
-        return searchControls;
-      }
-    }).once();
 
     replayAll();
 
-    handler.open(kc, DEFAULT_REALM, kerberosEnvMap);
+    handler.open(kc, DEFAULT_REALM, getKerberosEnv());
     handler.testAdministratorCredentials();
     handler.close();
   }
@@ -271,12 +258,6 @@ public class ADKerberosOperationHandlerTest extends KerberosOperationHandlerTest
     Injector injector = getInjector();
 
     PrincipalKeyCredential kc = new PrincipalKeyCredential(DEFAULT_ADMIN_PRINCIPAL, DEFAULT_ADMIN_PASSWORD);
-    Map<String, String> kerberosEnvMap = new HashMap<String, String>() {
-      {
-        put(ADKerberosOperationHandler.KERBEROS_ENV_LDAP_URL, DEFAULT_LDAP_URL);
-        put(ADKerberosOperationHandler.KERBEROS_ENV_PRINCIPAL_CONTAINER_DN, DEFAULT_PRINCIPAL_CONTAINER_DN);
-      }
-    };
 
     Capture<Name> capturedName = newCapture(CaptureType.ALL);
     Capture<Attributes> capturedAttributes = newCapture(CaptureType.ALL);
@@ -315,7 +296,7 @@ public class ADKerberosOperationHandlerTest extends KerberosOperationHandlerTest
 
     replayAll();
 
-    handler.open(kc, DEFAULT_REALM, kerberosEnvMap);
+    handler.open(kc, DEFAULT_REALM, getKerberosEnv());
     handler.createPrincipal("nn/c6501.ambari.apache.org", "secret", true);
     handler.createPrincipal("hdfs@" + DEFAULT_REALM, "secret", false);
     handler.close();
@@ -384,31 +365,26 @@ public class ADKerberosOperationHandlerTest extends KerberosOperationHandlerTest
     Injector injector = getInjector();
 
     PrincipalKeyCredential kc = new PrincipalKeyCredential(DEFAULT_ADMIN_PRINCIPAL, DEFAULT_ADMIN_PASSWORD);
-    Map<String, String> kerberosEnvMap = new HashMap<String, String>() {
-      {
-        put(ADKerberosOperationHandler.KERBEROS_ENV_LDAP_URL, DEFAULT_LDAP_URL);
-        put(ADKerberosOperationHandler.KERBEROS_ENV_PRINCIPAL_CONTAINER_DN, DEFAULT_PRINCIPAL_CONTAINER_DN);
-        put(ADKerberosOperationHandler.KERBEROS_ENV_AD_CREATE_ATTRIBUTES_TEMPLATE, "" +
-            "#set( $user = \"${principal_primary}-${principal_digest}\" )" +
-            "{" +
-            "  \"objectClass\": [" +
-            "    \"top\"," +
-            "    \"person\"," +
-            "    \"organizationalPerson\"," +
-            "    \"user\"" +
-            "  ]," +
-            "  \"cn\": \"$user\"," +
-            "  \"sAMAccountName\": \"$user.substring(0,20)\"," +
-            "  #if( $is_service )" +
-            "  \"servicePrincipalName\": \"$principal_name\"," +
-            "  #end" +
-            "  \"userPrincipalName\": \"$normalized_principal\"," +
-            "  \"unicodePwd\": \"$password\"," +
-            "  \"accountExpires\": \"0\"," +
-            "  \"userAccountControl\": \"66048\"" +
-            "}");
-      }
-    };
+    Map<String, String> kerberosEnvMap = new HashMap<>(getKerberosEnv());
+    kerberosEnvMap.put(ADKerberosOperationHandler.KERBEROS_ENV_AD_CREATE_ATTRIBUTES_TEMPLATE, "" +
+        "#set( $user = \"${principal_primary}-${principal_digest}\" )" +
+        "{" +
+        "  \"objectClass\": [" +
+        "    \"top\"," +
+        "    \"person\"," +
+        "    \"organizationalPerson\"," +
+        "    \"user\"" +
+        "  ]," +
+        "  \"cn\": \"$user\"," +
+        "  \"sAMAccountName\": \"$user.substring(0,20)\"," +
+        "  #if( $is_service )" +
+        "  \"servicePrincipalName\": \"$principal_name\"," +
+        "  #end" +
+        "  \"userPrincipalName\": \"$normalized_principal\"," +
+        "  \"unicodePwd\": \"$password\"," +
+        "  \"accountExpires\": \"0\"," +
+        "  \"userAccountControl\": \"66048\"" +
+        "}");
 
     Capture<Name> capturedName = newCapture();
     Capture<Attributes> capturedAttributes = newCapture();
@@ -491,9 +467,7 @@ public class ADKerberosOperationHandlerTest extends KerberosOperationHandlerTest
     Injector injector = getInjector();
 
     PrincipalKeyCredential kc = new PrincipalKeyCredential(DEFAULT_ADMIN_PRINCIPAL, DEFAULT_ADMIN_PASSWORD);
-    Map<String, String> kerberosEnvMap = new HashMap<>();
-    kerberosEnvMap.put(ADKerberosOperationHandler.KERBEROS_ENV_LDAP_URL, DEFAULT_LDAP_URL);
-    kerberosEnvMap.put(ADKerberosOperationHandler.KERBEROS_ENV_PRINCIPAL_CONTAINER_DN, DEFAULT_PRINCIPAL_CONTAINER_DN);
+    Map<String, String> kerberosEnvMap = new HashMap<>(getKerberosEnv());
     kerberosEnvMap.put(ADKerberosOperationHandler.KERBEROS_ENV_AD_CREATE_ATTRIBUTES_TEMPLATE, "" +
         "{" +
         "\"principal_digest\": \"$principal_digest\"," +
@@ -596,7 +570,7 @@ public class ADKerberosOperationHandlerTest extends KerberosOperationHandlerTest
 
     System.out.println("Test Admin Credentials: " + handler.testAdministratorCredentials());
     // does the principal already exist?
-    System.out.println("Principal exists: " + handler.principalExists("nn/c1508.ambari.apache.org"));
+    System.out.println("Principal exists: " + handler.principalExists("nn/c1508.ambari.apache.org", true));
 
     handler.close();
 
@@ -605,15 +579,15 @@ public class ADKerberosOperationHandlerTest extends KerberosOperationHandlerTest
     String evaluatedPrincipal;
 
     evaluatedPrincipal = "nn/c6501.ambari.apache.org@" + DEFAULT_REALM;
-    if (handler.principalExists(evaluatedPrincipal)) {
-      handler.setPrincipalPassword(evaluatedPrincipal, "some password");
+    if (handler.principalExists(evaluatedPrincipal, true)) {
+      handler.setPrincipalPassword(evaluatedPrincipal, "some password", true);
     } else {
       handler.createPrincipal(evaluatedPrincipal, "some password", true);
     }
 
     evaluatedPrincipal = "hdfs@" + DEFAULT_REALM;
-    if (handler.principalExists(evaluatedPrincipal)) {
-      handler.setPrincipalPassword(evaluatedPrincipal, "some password");
+    if (handler.principalExists(evaluatedPrincipal, false)) {
+      handler.setPrincipalPassword(evaluatedPrincipal, "some password", false);
     } else {
       handler.createPrincipal(evaluatedPrincipal, "some password", true);
     }
@@ -644,14 +618,14 @@ public class ADKerberosOperationHandlerTest extends KerberosOperationHandlerTest
     handler.open(credentials, realm, kerberosEnvMap);
 
     // remove the principal
-    handler.removePrincipal("abcdefg");
-    handler.removePrincipal("abcdefg/c1509.ambari.apache.org@" + DEFAULT_REALM);
+    handler.removePrincipal("abcdefg", false);
+    handler.removePrincipal("abcdefg/c1509.ambari.apache.org@" + DEFAULT_REALM, true);
 
     handler.createPrincipal("abcdefg/c1509.ambari.apache.org@" + DEFAULT_REALM, "some password", true);
     handler.createPrincipal("abcdefg@" + DEFAULT_REALM, "some password", false);
 
     //update the password
-    handler.setPrincipalPassword("abcdefg/c1509.ambari.apache.org@" + DEFAULT_REALM, "some password");
+    handler.setPrincipalPassword("abcdefg/c1509.ambari.apache.org@" + DEFAULT_REALM, "some password", true);
 
     handler.close();
   }
@@ -687,11 +661,7 @@ public class ADKerberosOperationHandlerTest extends KerberosOperationHandlerTest
 
     replayAll();
 
-    Map<String, String> kerberosConfiguration = new HashMap<>();
-    kerberosConfiguration.put(ADKerberosOperationHandler.KERBEROS_ENV_LDAP_URL, DEFAULT_LDAP_URL);
-    kerberosConfiguration.put(ADKerberosOperationHandler.KERBEROS_ENV_PRINCIPAL_CONTAINER_DN, DEFAULT_PRINCIPAL_CONTAINER_DN);
-
-    handler.open(new PrincipalKeyCredential("principal", "key"), "EXAMPLE.COM", kerberosConfiguration);
+    handler.open(new PrincipalKeyCredential("principal", "key"), "EXAMPLE.COM", getKerberosEnv());
 
     Properties properties = capturedProperties.getValue();
     Assert.assertNotNull(properties);
@@ -705,13 +675,78 @@ public class ADKerberosOperationHandlerTest extends KerberosOperationHandlerTest
   }
 
   private Injector getInjector() {
-    return Guice.createInjector(new AbstractModule() {
-      @Override
-      protected void configure() {
-        bind(Clusters.class).toInstance(createNiceMock(Clusters.class));
-        bind(Configuration.class).toInstance(createNiceMock(Configuration.class));
-        bind(OsFamily.class).toInstance(createNiceMock(OsFamily.class));
-      }
-    });
+    return injector;
+  }
+
+  @Override
+  protected KerberosOperationHandler createMockedHandler() throws KerberosOperationException {
+    return createMockedHandler(methodCreateInitialLdapContext);
+  }
+
+
+  private ADKerberosOperationHandler createMockedHandler(Method... mockedMethods) {
+    ADKerberosOperationHandler handler = createMockBuilder(ADKerberosOperationHandler.class)
+        .addMockedMethods(mockedMethods)
+        .createMock();
+    injector.injectMembers(handler);
+    return handler;
+  }
+
+
+  @Override
+  protected void setupOpenSuccess(KerberosOperationHandler handler) throws Exception {
+
+    ADKerberosOperationHandler adHandler = (ADKerberosOperationHandler) handler;
+
+    expect(adHandler.createInitialLdapContext(anyObject(Properties.class), isNull())).andReturn(ldapContext).anyTimes();
+  }
+
+  @Override
+  protected void setupOpenFailure(KerberosOperationHandler handler) throws Exception {
+    ADKerberosOperationHandler adHandler = (ADKerberosOperationHandler) handler;
+    expect(adHandler.createInitialLdapContext(anyObject(Properties.class), isNull())).andThrow(new AuthenticationException("Bogus error!")).anyTimes();
+  }
+
+  @Override
+  protected void setupPrincipalAlreadyExists(KerberosOperationHandler handler, boolean service) throws Exception {
+    setupPrincipalExists(handler, service);
+  }
+
+  @Override
+  protected void setupPrincipalDoesNotExist(KerberosOperationHandler handler, boolean service) throws Exception {
+    NamingEnumeration<SearchResult> results = createMock(NamingEnumeration.class);
+    results.close();
+    expectLastCall().once();
+    expect(results.hasMore()).andReturn(false).anyTimes();
+
+    expect(ldapContext.search(anyObject(Name.class), anyString(), anyObject(SearchControls.class)))
+        .andReturn(results)
+        .anyTimes();
+    ldapContext.close();
+    expectLastCall().once();
+  }
+
+  @Override
+  protected void setupPrincipalExists(KerberosOperationHandler handler, boolean service) throws Exception {
+    SearchResult result = createMock(SearchResult.class);
+    expect(result.getNameInNamespace()).andReturn("user/service dn").anyTimes();
+
+    NamingEnumeration<SearchResult> results = createMock(NamingEnumeration.class);
+    results.close();
+    expectLastCall().anyTimes();
+    expect(results.hasMore()).andReturn(true).once();
+    expect(results.next()).andReturn(result).once();
+    expect(results.hasMore()).andReturn(false).anyTimes();
+
+    expect(ldapContext.search(anyObject(Name.class), anyString(), anyObject(SearchControls.class)))
+        .andReturn(results)
+        .anyTimes();
+    ldapContext.close();
+    expectLastCall().once();
+  }
+
+  @Override
+  protected Map<String, String> getKerberosEnv() {
+    return KERBEROS_ENV_MAP;
   }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f844e5f3/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/IPAKerberosOperationHandlerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/IPAKerberosOperationHandlerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/IPAKerberosOperationHandlerTest.java
index f2a09ba..558ca79 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/IPAKerberosOperationHandlerTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/IPAKerberosOperationHandlerTest.java
@@ -18,36 +18,26 @@
 
 package org.apache.ambari.server.serveraction.kerberos;
 
+import static org.easymock.EasyMock.anyObject;
 import static org.easymock.EasyMock.expect;
 import static org.easymock.EasyMock.replay;
 
+import java.lang.reflect.Method;
 import java.util.HashMap;
 import java.util.Map;
 
-import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.configuration.Configuration;
-import org.apache.ambari.server.security.credential.PrincipalKeyCredential;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.stack.OsFamily;
+import org.apache.ambari.server.utils.ShellCommandUtil;
 import org.easymock.EasyMock;
 import org.junit.BeforeClass;
-import org.junit.Test;
 
 import com.google.inject.AbstractModule;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 
-import junit.framework.Assert;
-
-public class IPAKerberosOperationHandlerTest extends KerberosOperationHandlerTest {
-  private static final String DEFAULT_ADMIN_PRINCIPAL = "admin";
-  private static final String DEFAULT_ADMIN_PASSWORD = "Hadoop12345";
-
-  private static final String DEFAULT_REALM = "IPA01.LOCAL";
-
-  private static Injector injector;
-
-  private static boolean hasIpa = false;
+public class IPAKerberosOperationHandlerTest extends KDCKerberosOperationHandlerTest {
 
   private static final Map<String, String> KERBEROS_ENV_MAP = new HashMap<String, String>() {
     {
@@ -58,8 +48,10 @@ public class IPAKerberosOperationHandlerTest extends KerberosOperationHandlerTes
     }
   };
 
+  private static Injector injector;
+
   @BeforeClass
-  public static void beforeClass() throws AmbariException {
+  public static void beforeIPAKerberosOperationHandlerTest() throws Exception {
     injector = Guice.createInjector(new AbstractModule() {
       @Override
       protected void configure() {
@@ -72,85 +64,74 @@ public class IPAKerberosOperationHandlerTest extends KerberosOperationHandlerTes
         bind(OsFamily.class).toInstance(EasyMock.createNiceMock(OsFamily.class));
       }
     });
-    if (System.getenv("HAS_IPA") != null) {
-      hasIpa = true;
-    }
   }
 
-  @Test
-  public void testSetPrincipalPasswordExceptions() throws Exception {
-    if (!hasIpa) {
-      return;
-    }
+  @Override
+  protected IPAKerberosOperationHandler createMockedHandler(Method... mockedMethods) {
+    IPAKerberosOperationHandler handler = createMockBuilder(IPAKerberosOperationHandler.class)
+        .addMockedMethods(mockedMethods)
+        .createMock();
+    injector.injectMembers(handler);
+    return handler;
+  }
 
-    IPAKerberosOperationHandler handler = injector.getInstance(IPAKerberosOperationHandler.class);
-    handler.open(new PrincipalKeyCredential(DEFAULT_ADMIN_PRINCIPAL, DEFAULT_ADMIN_PASSWORD), DEFAULT_REALM, KERBEROS_ENV_MAP);
-    try {
-      handler.setPrincipalPassword(DEFAULT_ADMIN_PRINCIPAL, null);
-      Assert.fail("KerberosOperationException not thrown for null password");
-    } catch (Throwable t) {
-      Assert.assertEquals(KerberosOperationException.class, t.getClass());
-    }
+  @Override
+  protected Map<String, String> getKerberosEnv() {
+    return KERBEROS_ENV_MAP;
+  }
 
-    try {
-      handler.setPrincipalPassword(DEFAULT_ADMIN_PRINCIPAL, "");
-      Assert.fail("KerberosOperationException not thrown for empty password");
-      handler.createPrincipal("", "1234", false);
-      Assert.fail("AmbariException not thrown for empty principal");
-    } catch (Throwable t) {
-      Assert.assertEquals(KerberosOperationException.class, t.getClass());
+  @Override
+  protected void setupPrincipalAlreadyExists(KerberosOperationHandler handler, boolean service) throws Exception {
+    ShellCommandUtil.Result result = createMock(ShellCommandUtil.Result.class);
+    expect(result.getExitCode()).andReturn(1).anyTimes();
+    expect(result.isSuccessful()).andReturn(false).anyTimes();
+    if(service) {
+      expect(result.getStderr()).andReturn("ipa: ERROR: service with name \"service/host@EXAMPLE.COM\" already exists").anyTimes();
     }
-
-    try {
-      handler.setPrincipalPassword(null, DEFAULT_ADMIN_PASSWORD);
-      Assert.fail("KerberosOperationException not thrown for null principal");
-    } catch (Throwable t) {
-      Assert.assertEquals(KerberosOperationException.class, t.getClass());
+    else {
+      expect(result.getStderr()).andReturn("ipa: ERROR: user with name \"user\" already exists").anyTimes();
     }
+    expect(result.getStdout()).andReturn("").anyTimes();
 
-    try {
-      handler.setPrincipalPassword("", DEFAULT_ADMIN_PASSWORD);
-      Assert.fail("KerberosOperationException not thrown for empty principal");
-    } catch (Throwable t) {
-      Assert.assertEquals(KerberosOperationException.class, t.getClass());
-    }
+    expect(handler.executeCommand(arrayContains(new String[]{"ipa", (service) ? "service-add" : "user-add"}), anyObject(Map.class), anyObject(KDCKerberosOperationHandler.InteractivePasswordHandler.class)))
+        .andReturn(result)
+        .anyTimes();
   }
 
-  @Test
-  public void testCreateServicePrincipal_Exceptions() throws Exception {
-    if (!hasIpa) {
-      return;
-    }
-
-    IPAKerberosOperationHandler handler = new IPAKerberosOperationHandler();
-    handler.open(new PrincipalKeyCredential(DEFAULT_ADMIN_PRINCIPAL, DEFAULT_ADMIN_PASSWORD), DEFAULT_REALM, KERBEROS_ENV_MAP);
+  @Override
+  protected void setupPrincipalDoesNotExist(KerberosOperationHandler handler, boolean service) throws Exception {
+    ShellCommandUtil.Result result = createMock(ShellCommandUtil.Result.class);
+    expect(result.getExitCode()).andReturn(2).anyTimes();
+    expect(result.isSuccessful()).andReturn(false).anyTimes();
+    expect(result.getStderr()).andReturn(String.format("ipa: ERROR: %s: user not found", (service) ? "service/host" : "user")).anyTimes();
+    expect(result.getStdout()).andReturn("").anyTimes();
 
-    try {
-      handler.createPrincipal(DEFAULT_ADMIN_PRINCIPAL, null, false);
-      Assert.fail("KerberosOperationException not thrown for null password");
-    } catch (Throwable t) {
-      Assert.fail("KerberosOperationException thrown on null password with IPA");
-    }
 
-    try {
-      handler.createPrincipal(DEFAULT_ADMIN_PRINCIPAL, "", false);
-    } catch (Throwable t) {
-      Assert.fail("KerberosOperationException thrown for empty password");
-    }
-
-    try {
-      handler.createPrincipal(null, DEFAULT_ADMIN_PASSWORD, false);
-      Assert.fail("KerberosOperationException not thrown for null principal");
-    } catch (Throwable t) {
-      Assert.assertEquals(KerberosOperationException.class, t.getClass());
-    }
-
-    try {
-      handler.createPrincipal("", DEFAULT_ADMIN_PASSWORD, false);
-      Assert.fail("KerberosOperationException not thrown for empty principal");
-    } catch (Throwable t) {
-      Assert.assertEquals(KerberosOperationException.class, t.getClass());
-    }
+    expect(handler.executeCommand(arrayContains(new String[]{"ipa", (service) ? "service-show" : "user-show"}), anyObject(Map.class), anyObject(KDCKerberosOperationHandler.InteractivePasswordHandler.class)))
+        .andReturn(result)
+        .anyTimes();
   }
 
+  @Override
+  protected void setupPrincipalExists(KerberosOperationHandler handler, boolean service) throws Exception {
+    ShellCommandUtil.Result result = createMock(ShellCommandUtil.Result.class);
+    expect(result.getExitCode()).andReturn(0).anyTimes();
+    expect(result.isSuccessful()).andReturn(true).anyTimes();
+    expect(result.getStderr()).andReturn("").anyTimes();
+    expect(result.getStdout()).andReturn(String.format("  User login: %s\n" +
+        "  Last name: User\n" +
+        "  Home directory: /home/user\n" +
+        "  Login shell: /bin/bash\n" +
+        "  Principal alias: user@EXAMPLE.COM\n" +
+        "  UID: 324200000\n" +
+        "  GID: 324200000\n" +
+        "  Account disabled: False\n" +
+        "  Password: True\n" +
+        "  Member of groups: users\n" +
+        "  Kerberos keys available: True", (service) ? "service/host" : "user")).anyTimes();
+
+    expect(handler.executeCommand(arrayContains(new String[]{"ipa", (service) ? "service-show" : "user-show"}), anyObject(Map.class), anyObject(KDCKerberosOperationHandler.InteractivePasswordHandler.class)))
+        .andReturn(result)
+        .anyTimes();
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f844e5f3/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/KDCKerberosOperationHandlerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/KDCKerberosOperationHandlerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/KDCKerberosOperationHandlerTest.java
new file mode 100644
index 0000000..271c787
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/KDCKerberosOperationHandlerTest.java
@@ -0,0 +1,152 @@
+/*
+ * 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 static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.expect;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+
+import org.apache.ambari.server.utils.ShellCommandUtil;
+import org.apache.commons.lang.StringUtils;
+import org.easymock.EasyMock;
+import org.easymock.IArgumentMatcher;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import junit.framework.Assert;
+
+abstract public class KDCKerberosOperationHandlerTest extends KerberosOperationHandlerTest {
+
+  static Method methodExecuteCommand;
+
+  @BeforeClass
+  public static void beforeKDCKerberosOperationHandlerTest() throws Exception {
+    methodExecuteCommand = KDCKerberosOperationHandler.class.getDeclaredMethod("executeCommand", String[].class, Map.class, ShellCommandUtil.InteractiveHandler.class);
+  }
+
+  @Test
+  public void testInteractivePasswordHandler() {
+    KDCKerberosOperationHandler.InteractivePasswordHandler handler = new KDCKerberosOperationHandler.InteractivePasswordHandler("admin_password", "user_password");
+
+    handler.start();
+    Assert.assertEquals("admin_password", handler.getResponse("password"));
+    Assert.assertFalse(handler.done());
+    Assert.assertEquals("user_password", handler.getResponse("password"));
+    Assert.assertFalse(handler.done());
+    Assert.assertEquals("user_password", handler.getResponse("password"));
+    Assert.assertTrue(handler.done());
+
+    // Test restarting
+    handler.start();
+    Assert.assertEquals("admin_password", handler.getResponse("password"));
+    Assert.assertFalse(handler.done());
+    Assert.assertEquals("user_password", handler.getResponse("password"));
+    Assert.assertFalse(handler.done());
+    Assert.assertEquals("user_password", handler.getResponse("password"));
+    Assert.assertTrue(handler.done());
+  }
+
+  @Override
+  protected KerberosOperationHandler createMockedHandler() throws KerberosOperationException {
+    return createMockedHandler(methodExecuteCommand);
+  }
+
+  @Override
+  protected void setupOpenSuccess(KerberosOperationHandler handler) throws Exception {
+    ShellCommandUtil.Result result = createMock(ShellCommandUtil.Result.class);
+    expect(result.isSuccessful()).andReturn(true);
+
+    expect(handler.executeCommand(arrayContains("/usr/bin/kinit"), anyObject(Map.class), anyObject(KDCKerberosOperationHandler.InteractivePasswordHandler.class)))
+        .andReturn(result)
+        .anyTimes();
+  }
+
+  @Override
+  protected void setupOpenFailure(KerberosOperationHandler handler) throws Exception {
+    ShellCommandUtil.Result result = createMock(ShellCommandUtil.Result.class);
+    expect(result.isSuccessful()).andReturn(false).once();
+    expect(result.getExitCode()).andReturn(-1).once();
+    expect(result.getStdout()).andReturn("STDOUT data").once();
+    expect(result.getStderr()).andReturn("STDERR data").once();
+
+    expect(handler.executeCommand(arrayContains("/usr/bin/kinit"), anyObject(Map.class), anyObject(KDCKerberosOperationHandler.InteractivePasswordHandler.class)))
+        .andReturn(result)
+        .anyTimes();
+  }
+
+  protected abstract KDCKerberosOperationHandler createMockedHandler(Method... mockedMethods);
+
+  public static class ArrayContains implements IArgumentMatcher {
+
+    private String[] startItems;
+
+    ArrayContains(String startItem) {
+      this.startItems = new String[]{startItem};
+    }
+
+    ArrayContains(String[] startItems) {
+      this.startItems = startItems;
+    }
+
+    @Override
+    public boolean matches(Object o) {
+      if (o instanceof String[]) {
+        String[] array = (String[]) o;
+
+        for (String item : startItems) {
+          boolean valueContains = false;
+          for (String value : array) {
+            if (value.contains(item)) {
+              valueContains = true;
+              break;
+            }
+          }
+
+          if (!valueContains) {
+            return false;
+          }
+        }
+
+        return true;
+      }
+
+      return false;
+    }
+
+    @Override
+    public void appendTo(StringBuffer stringBuffer) {
+      stringBuffer.append("arrayContains(");
+      stringBuffer.append(StringUtils.join(startItems, ", "));
+      stringBuffer.append("\")");
+    }
+  }
+
+  static String[] arrayContains(String in) {
+    EasyMock.reportMatcher(new ArrayContains(in));
+    return null;
+  }
+
+  static String[] arrayContains(String[] in) {
+    EasyMock.reportMatcher(new ArrayContains(in));
+    return null;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f844e5f3/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/KerberosOperationHandlerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/KerberosOperationHandlerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/KerberosOperationHandlerTest.java
index 88c841c..9d1e8e0 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/KerberosOperationHandlerTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/KerberosOperationHandlerTest.java
@@ -40,10 +40,128 @@ import junit.framework.Assert;
 
 public abstract class KerberosOperationHandlerTest extends EasyMockSupport {
 
+  static final String DEFAULT_ADMIN_PRINCIPAL = "admin";
+  static final String DEFAULT_ADMIN_PASSWORD = "hadoop";
+  static final String DEFAULT_REALM = "EXAMPLE.COM";
+  static final PrincipalKeyCredential DEFAULT_ADMIN_CREDENTIALS = new PrincipalKeyCredential(DEFAULT_ADMIN_PRINCIPAL, DEFAULT_ADMIN_PASSWORD);
+
   @Rule
   public TemporaryFolder folder = new TemporaryFolder();
 
   @Test
+  public void testOpenSucceeded() throws Exception {
+    KerberosOperationHandler handler = createMockedHandler();
+
+    setupOpenSuccess(handler);
+
+    replayAll();
+
+    handler.open(getAdminCredentials(), DEFAULT_REALM, getKerberosEnv());
+
+    verifyAll();
+
+    Assert.assertTrue(handler.isOpen());
+  }
+
+  @Test
+  public void testOpenFailed() throws Exception {
+    KerberosOperationHandler handler = createMockedHandler();
+
+    setupOpenFailure(handler);
+
+    replayAll();
+
+    try {
+      handler.open(getAdminCredentials(), DEFAULT_REALM, getKerberosEnv());
+      Assert.fail("KerberosAdminAuthenticationException expected");
+    } catch (KerberosAdminAuthenticationException e) {
+      // This is expected
+    }
+
+    verifyAll();
+
+    Assert.assertFalse(handler.isOpen());
+  }
+
+  @Test(expected = KerberosPrincipalAlreadyExistsException.class)
+  public void testCreateUserPrincipalPrincipalAlreadyExists() throws Exception {
+    testCreatePrincipalPrincipalAlreadyExists(false);
+  }
+
+  @Test(expected = KerberosPrincipalAlreadyExistsException.class)
+  public void testCreateServicePrincipalPrincipalAlreadyExists() throws Exception {
+    testCreatePrincipalPrincipalAlreadyExists(true);
+  }
+
+  private void testCreatePrincipalPrincipalAlreadyExists(boolean service) throws Exception {
+    KerberosOperationHandler handler = createMockedHandler();
+
+    setupOpenSuccess(handler);
+    setupPrincipalAlreadyExists(handler, service);
+
+    replayAll();
+
+    handler.open(getAdminCredentials(), DEFAULT_REALM, getKerberosEnv());
+    handler.createPrincipal(createPrincipal(service), "password", service);
+    handler.close();
+
+    verifyAll();
+
+  }
+
+
+  @Test
+  public void testUserPrincipalExistsNotFound() throws Exception {
+    testPrincipalExistsNotFound(false);
+  }
+
+  @Test
+  public void testServicePrincipalExistsNotFound() throws Exception {
+    testPrincipalExistsNotFound(true);
+  }
+
+  private void testPrincipalExistsNotFound(boolean service) throws Exception {
+    KerberosOperationHandler handler = createMockedHandler();
+
+    setupOpenSuccess(handler);
+    setupPrincipalDoesNotExist(handler, service);
+
+    replayAll();
+
+    handler.open(getAdminCredentials(), DEFAULT_REALM, getKerberosEnv());
+    Assert.assertFalse(handler.principalExists(createPrincipal(service), service));
+    handler.close();
+
+    verifyAll();
+  }
+
+  @Test
+  public void testUserPrincipalExistsFound() throws Exception {
+    testPrincipalExistsFound(false);
+  }
+
+  @Test
+  public void testServicePrincipalExistsFound() throws Exception {
+    testPrincipalExistsFound(true);
+  }
+
+  private void testPrincipalExistsFound(boolean service) throws Exception {
+    KerberosOperationHandler handler = createMockedHandler();
+
+    setupOpenSuccess(handler);
+    setupPrincipalExists(handler, service);
+
+    replayAll();
+
+    handler.open(getAdminCredentials(), DEFAULT_REALM, getKerberosEnv());
+    Assert.assertTrue(handler.principalExists(createPrincipal(service), service));
+    handler.close();
+
+    verifyAll();
+
+  }
+
+  @Test
   public void testCreateKeytabFileOneAtATime() throws Exception {
     KerberosOperationHandler handler = createHandler();
     File file = folder.newFile();
@@ -285,7 +403,7 @@ public abstract class KerberosOperationHandlerTest extends EasyMockSupport {
   public void testAdminCredentialsNullCredential() throws KerberosOperationException {
     KerberosOperationHandler handler = createHandler();
 
-    PrincipalKeyCredential credentials = new PrincipalKeyCredential("principal", (char[])null);
+    PrincipalKeyCredential credentials = new PrincipalKeyCredential("principal", (char[]) null);
     handler.setAdministratorCredential(credentials);
   }
 
@@ -301,10 +419,10 @@ public abstract class KerberosOperationHandlerTest extends EasyMockSupport {
   public void testSetExecutableSearchPaths() throws KerberosOperationException {
     KerberosOperationHandler handler = createHandler();
 
-    handler.setExecutableSearchPaths((String)null);
+    handler.setExecutableSearchPaths((String) null);
     Assert.assertNull(handler.getExecutableSearchPaths());
 
-    handler.setExecutableSearchPaths((String[])null);
+    handler.setExecutableSearchPaths((String[]) null);
     Assert.assertNull(handler.getExecutableSearchPaths());
 
     handler.setExecutableSearchPaths("");
@@ -341,6 +459,24 @@ public abstract class KerberosOperationHandlerTest extends EasyMockSupport {
     Assert.assertEquals("path3/", handler.getExecutableSearchPaths()[2]);
   }
 
+  protected abstract KerberosOperationHandler createMockedHandler() throws KerberosOperationException;
+
+  protected abstract void setupOpenSuccess(KerberosOperationHandler handler) throws Exception;
+
+  protected abstract void setupOpenFailure(KerberosOperationHandler handler) throws Exception;
+
+  protected abstract void setupPrincipalAlreadyExists(KerberosOperationHandler handler, boolean service) throws Exception;
+
+  protected abstract void setupPrincipalDoesNotExist(KerberosOperationHandler handler, boolean service) throws Exception;
+
+  protected abstract void setupPrincipalExists(KerberosOperationHandler handler, boolean service) throws Exception;
+
+  protected abstract Map<String, String> getKerberosEnv();
+
+  protected PrincipalKeyCredential getAdminCredentials() {
+    return DEFAULT_ADMIN_CREDENTIALS;
+  }
+
   private KerberosOperationHandler createHandler() throws KerberosOperationException {
     KerberosOperationHandler handler = new KerberosOperationHandler() {
 
@@ -357,7 +493,7 @@ public abstract class KerberosOperationHandlerTest extends EasyMockSupport {
       }
 
       @Override
-      public boolean principalExists(String principal) throws KerberosOperationException {
+      public boolean principalExists(String principal, boolean service) throws KerberosOperationException {
         return false;
       }
 
@@ -367,12 +503,12 @@ public abstract class KerberosOperationHandlerTest extends EasyMockSupport {
       }
 
       @Override
-      public Integer setPrincipalPassword(String principal, String password) throws KerberosOperationException {
+      public Integer setPrincipalPassword(String principal, String password, boolean service) throws KerberosOperationException {
         return 0;
       }
 
       @Override
-      public boolean removePrincipal(String principal) throws KerberosOperationException {
+      public boolean removePrincipal(String principal, boolean service) throws KerberosOperationException {
         return false;
       }
     };
@@ -380,4 +516,8 @@ public abstract class KerberosOperationHandlerTest extends EasyMockSupport {
     handler.open(new PrincipalKeyCredential("admin/admin", "hadoop"), "EXAMPLE.COM", null);
     return handler;
   }
+
+  private String createPrincipal(boolean service) {
+    return String.format("%s@%s", (service) ? "service/host" : "user", DEFAULT_REALM);
+  }
 }