You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by rl...@apache.org on 2015/01/13 19:27:54 UTC

[2/2] ambari git commit: AMBARI-9014. Design admin principal session expiration handling API call (rlevas)

AMBARI-9014. Design admin principal session expiration handling API call (rlevas)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/efe79f01
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/efe79f01
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/efe79f01

Branch: refs/heads/trunk
Commit: efe79f015a1ea995a62db922cdbf9edb47c8bcf8
Parents: e67c5ea
Author: Robert Levas <rl...@hortonworks.com>
Authored: Tue Jan 13 13:27:14 2015 -0500
Committer: Robert Levas <rl...@hortonworks.com>
Committed: Tue Jan 13 13:27:14 2015 -0500

----------------------------------------------------------------------
 .../server/controller/ControllerModule.java     |   3 +
 .../server/controller/KerberosHelper.java       |  81 +++-
 .../kerberos/ADKerberosOperationHandler.java    | 292 +++++++------
 .../kerberos/CreateKeytabFilesServerAction.java |  20 +-
 .../kerberos/CreatePrincipalsServerAction.java  |  60 +--
 .../kerberos/KerberosOperationHandler.java      | 150 ++++---
 .../KerberosOperationHandlerFactory.java        |   6 +-
 .../kerberos/KerberosServerAction.java          |  17 +-
 .../kerberos/MITKerberosOperationHandler.java   | 432 +++++++++----------
 .../server/controller/KerberosHelperTest.java   |  78 +++-
 .../ADKerberosOperationHandlerTest.java         | 241 +++++++++--
 .../AbstractKerberosOperationHandlerTest.java   | 245 -----------
 .../KerberosOperationHandlerFactoryTest.java    |   4 +-
 .../kerberos/KerberosOperationHandlerTest.java  | 206 ++++++++-
 .../MITKerberosOperationHandlerTest.java        | 320 +++++++++++++-
 15 files changed, 1377 insertions(+), 778 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/efe79f01/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
index 9662669..8647f26 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
@@ -68,6 +68,7 @@ import org.apache.ambari.server.scheduler.ExecutionScheduler;
 import org.apache.ambari.server.scheduler.ExecutionSchedulerImpl;
 import org.apache.ambari.server.security.SecurityHelper;
 import org.apache.ambari.server.security.SecurityHelperImpl;
+import org.apache.ambari.server.serveraction.kerberos.KerberosOperationHandlerFactory;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.Config;
@@ -201,6 +202,8 @@ public class ControllerModule extends AbstractModule {
     bind(SessionManager.class).toInstance(sessionManager);
     bind(SessionIdManager.class).toInstance(sessionIdManager);
 
+    bind(KerberosOperationHandlerFactory.class);
+
     bind(Configuration.class).toInstance(configuration);
     bind(OsFamily.class).toInstance(os_family);
     bind(HostsMap.class).toInstance(hostsMap);

http://git-wip-us.apache.org/repos/asf/ambari/blob/efe79f01/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelper.java
index 0533228..ef0d096 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelper.java
@@ -102,6 +102,9 @@ public class KerberosHelper {
   @Inject
   private ConfigHelper configHelper;
 
+  @Inject
+  private KerberosOperationHandlerFactory kerberosOperationHandlerFactory;
+
   /**
    * The Handler implementation that provides the logic to enable Kerberos
    */
@@ -384,22 +387,86 @@ public class KerberosHelper {
         // If there are ServiceComponentHosts to process, make sure the administrator credentials
         // are available
         if (!serviceComponentHostsToProcess.isEmpty()) {
-          if (getEncryptedAdministratorCredentials(cluster) == null) {
+          try {
+            String credentials = getEncryptedAdministratorCredentials(cluster);
+            if (credentials == null) {
+              throw new IllegalArgumentException(
+                  "Missing KDC administrator credentials.\n" +
+                      "The KDC administrator credentials must be set in session by updating the relevant Cluster resource." +
+                      "This may be done by issuing a PUT to the api/v1/clusters/(cluster name) API entry point with the following payload:\n" +
+                      "{\n" +
+                      "  \"session_attributes\" : {\n" +
+                      "    \"kerberos_admin\" : {\"principal\" : \"(PRINCIPAL)\", \"password\" : \"(PASSWORD)\"}\n" +
+                      "  }\n" +
+                      "}"
+              );
+            } else {
+              KerberosOperationHandler operationHandler = kerberosOperationHandlerFactory.getKerberosOperationHandler(kdcType);
+
+              if (operationHandler == null) {
+                throw new AmbariException("Failed to get an appropriate Kerberos operation handler.");
+              } else {
+                byte[] key = Integer.toHexString(cluster.hashCode()).getBytes();
+                KerberosCredential kerberosCredentials = KerberosCredential.decrypt(credentials, key);
+
+                try {
+                  operationHandler.open(kerberosCredentials, realm);
+                  if (!operationHandler.testAdministratorCredentials()) {
+                    throw new IllegalArgumentException(
+                        "Invalid KDC administrator credentials.\n" +
+                            "The KDC administrator credentials must be set in session by updating the relevant Cluster resource." +
+                            "This may be done by issuing a PUT to the api/v1/clusters/(cluster name) API entry point with the following payload:\n" +
+                            "{\n" +
+                            "  \"session_attributes\" : {\n" +
+                            "    \"kerberos_admin\" : {\"principal\" : \"(PRINCIPAL)\", \"password\" : \"(PASSWORD)\"}\n" +
+                            "  }\n" +
+                            "}"
+                    );
+                  }
+                } catch (KerberosAdminAuthenticationException e) {
+                  throw new IllegalArgumentException(
+                      "Invalid KDC administrator credentials.\n" +
+                          "The KDC administrator credentials must be set in session by updating the relevant Cluster resource." +
+                          "This may be done by issuing a PUT to the api/v1/clusters/(cluster name) API entry point with the following payload:\n" +
+                          "{\n" +
+                          "  \"session_attributes\" : {\n" +
+                          "    \"kerberos_admin\" : {\"principal\" : \"(PRINCIPAL)\", \"password\" : \"(PASSWORD)\"}\n" +
+                          "  }\n" +
+                          "}",
+                      e
+                  );
+                } catch (KerberosKDCConnectionException e) {
+                  throw new AmbariException("Failed to connect to KDC - " + e.getMessage() + "\n" +
+                      "Update the KDC settings in krb5-conf and kerberos-env configurations to correct this issue.",
+                      e);
+                } catch (KerberosOperationException e) {
+                  throw new AmbariException(e.getMessage(), e);
+                } finally {
+                  try {
+                    operationHandler.close();
+                  } catch (KerberosOperationException e) {
+                    // Ignore this...
+                  }
+                }
+              }
+            }
+          } catch (IllegalArgumentException e) {
             try {
               FileUtils.deleteDirectory(dataDirectory);
-            } catch (IOException e) {
+            } catch (Throwable t) {
               LOG.warn(String.format("The data directory (%s) was not deleted due to an error condition - {%s}",
-                  dataDirectory.getAbsolutePath(), e.getMessage()), e);
+                  dataDirectory.getAbsolutePath(), t.getMessage()), t);
             }
-            throw new AmbariException("Missing KDC administrator credentials");
+
+            throw e;
           }
 
           // Determine if the any auth_to_local configurations need to be set dynamically
           // Lazily create the auth_to_local rules
           String authToLocal = null;
-          for(Map<String, String> configuration: kerberosConfigurations.values()) {
-            for(Map.Entry<String,String> entry: configuration.entrySet()) {
-              if("_AUTH_TO_LOCAL_RULES".equals(entry.getValue())) {
+          for (Map<String, String> configuration : kerberosConfigurations.values()) {
+            for (Map.Entry<String, String> entry : configuration.entrySet()) {
+              if ("_AUTH_TO_LOCAL_RULES".equals(entry.getValue())) {
                 if (authToLocal == null) {
                   authToLocal = authToLocalBuilder.generate(realm);
                 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/efe79f01/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/ADKerberosOperationHandler.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/ADKerberosOperationHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/ADKerberosOperationHandler.java
index a8eed2b..01913e4 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/ADKerberosOperationHandler.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/ADKerberosOperationHandler.java
@@ -19,18 +19,16 @@
 package org.apache.ambari.server.serveraction.kerberos;
 
 
-import org.apache.ambari.server.AmbariException;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
 import javax.naming.*;
 import javax.naming.directory.*;
+import javax.naming.ldap.Control;
 import javax.naming.ldap.InitialLdapContext;
 import javax.naming.ldap.LdapContext;
 import java.io.UnsupportedEncodingException;
-import java.util.HashSet;
 import java.util.Properties;
-import java.util.Set;
 
 /**
  * Implementation of <code>KerberosOperationHandler</code> to created principal in Active Directory
@@ -41,28 +39,22 @@ public class ADKerberosOperationHandler extends KerberosOperationHandler {
 
   private static final String LDAP_CONTEXT_FACTORY_CLASS = "com.sun.jndi.ldap.LdapCtxFactory";
 
-  private String adminPrincipal;
-  private String adminPassword;
-  private String realm;
-
   private String ldapUrl;
   private String principalContainerDn;
 
-  private static final int ONELEVEL_SCOPE = SearchControls.ONELEVEL_SCOPE;
+  private static final int ONE_LEVEL_SCOPE = SearchControls.ONELEVEL_SCOPE;
   private static final String LDAP_ATUH_MECH_SIMPLE = "simple";
 
   private LdapContext ldapContext;
-
   private SearchControls searchControls;
 
   /**
    * Prepares and creates resources to be used by this KerberosOperationHandler.
-   * This method in this class would always throw <code>AmabriException</code> reporting
+   * This method in this class would always throw <code>KerberosOperationException</code> reporting
    * ldapUrl is not provided.
-   * Please use <code>open(KerberosCredential administratorCredentials, String defaultRealm,
+   * Use <code>open(KerberosCredential administratorCredentials, String defaultRealm,
    * String ldapUrl, String principalContainerDn)</code> for successful operation.
    * <p/>
-   * <p/>
    * It is expected that this KerberosOperationHandler will not be used before this call.
    *
    * @param administratorCredentials a KerberosCredential containing the administrative credentials
@@ -71,7 +63,7 @@ public class ADKerberosOperationHandler extends KerberosOperationHandler {
    */
   @Override
   public void open(KerberosCredential administratorCredentials, String realm)
-    throws AmbariException {
+      throws KerberosOperationException {
     open(administratorCredentials, realm, null, null);
   }
 
@@ -85,56 +77,42 @@ public class ADKerberosOperationHandler extends KerberosOperationHandler {
    * @param realm                    a String declaring the default Kerberos realm (or domain)
    * @param ldapUrl                  ldapUrl of ldap back end where principals would be created
    * @param principalContainerDn     DN of the container in ldap back end where principals would be created
+   * @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
    */
   @Override
   public void open(KerberosCredential administratorCredentials, String realm,
                    String ldapUrl, String principalContainerDn)
-    throws AmbariException {
+      throws KerberosOperationException {
+
+    if (isOpen()) {
+      close();
+    }
+
     if (administratorCredentials == null) {
-      throw new AmbariException("admininstratorCredential not provided");
+      throw new KerberosAdminAuthenticationException("administrator Credential not provided");
     }
     if (realm == null) {
-      throw new AmbariException("realm not provided");
+      throw new KerberosRealmException("realm not provided");
     }
     if (ldapUrl == null) {
-      throw new AmbariException("ldapUrl not provided");
+      throw new KerberosKDCConnectionException("ldapUrl not provided");
     }
     if (principalContainerDn == null) {
-      throw new AmbariException("principalContainerDn not provided");
+      throw new KerberosLDAPContainerException("principalContainerDn not provided");
     }
-    this.adminPrincipal = administratorCredentials.getPrincipal();
-    this.adminPassword = administratorCredentials.getPassword();
-    this.realm = realm;
-    this.ldapUrl = ldapUrl;
-    this.principalContainerDn = principalContainerDn;
-    createLdapContext();
-  }
-
-  private void createLdapContext() throws AmbariException {
-    LOG.info("Creating ldap context");
-
-    Properties env = new Properties();
-    env.put(Context.INITIAL_CONTEXT_FACTORY, LDAP_CONTEXT_FACTORY_CLASS);
-    env.put(Context.PROVIDER_URL, ldapUrl);
-    env.put(Context.SECURITY_PRINCIPAL, adminPrincipal);
-    env.put(Context.SECURITY_CREDENTIALS, adminPassword);
-    env.put(Context.SECURITY_AUTHENTICATION, LDAP_ATUH_MECH_SIMPLE);
-    env.put(Context.REFERRAL, "follow");
 
-    try {
-      ldapContext = new InitialLdapContext(env, null);
-    } catch (NamingException ne) {
-      LOG.error("Can not created ldapContext", ne);
-      throw new AmbariException("Can not created ldapContext", ne);
-    }
+    setAdministratorCredentials(administratorCredentials);
+    setDefaultRealm(realm);
 
-    searchControls = new SearchControls();
-    searchControls.setSearchScope(ONELEVEL_SCOPE);
+    this.ldapUrl = ldapUrl;
+    this.principalContainerDn = principalContainerDn;
+    this.ldapContext = createLdapContext();
+    this.searchControls = createSearchControls();
 
-    Set<String> userSearchAttributes = new HashSet<String>();
-    userSearchAttributes.add("cn");
-    searchControls.setReturningAttributes(userSearchAttributes.toArray(
-      new String[userSearchAttributes.size()]));
+    setOpen(true);
   }
 
   /**
@@ -143,37 +121,16 @@ public class ADKerberosOperationHandler extends KerberosOperationHandler {
    * It is expected that this KerberosOperationHandler will not be used after this call.
    */
   @Override
-  public void close() {
-    try {
-      if (ldapContext != null) {
+  public void close() throws KerberosOperationException {
+    if (ldapContext != null) {
+      try {
         ldapContext.close();
+      } catch (NamingException e) {
+        throw new KerberosOperationException("Unexpected error", e);
       }
-    } catch (NamingException ne) {
-      // ignored, nothing we could do about it
     }
 
-  }
-
-  /**
-   * Maps Keberos realm name to AD dc tree syntaz
-   *
-   * @param realm kerberos realm name
-   * @return mapped dc tree string
-   */
-  private static String realmToDcs(String realm) {
-    if (realm == null || realm.isEmpty()) {
-      return realm;
-    }
-    String[] tokens = realm.split("\\.");
-    StringBuilder sb = new StringBuilder();
-    int len = tokens.length;
-    if (len > 0) {
-      sb.append("dc=").append(tokens[0]);
-    }
-    for (int i = 1; i < len; i++)   {
-      sb.append(",").append("dc=").append(tokens[i]);
-    }
-    return sb.toString();
+    setOpen(false);
   }
 
   /**
@@ -183,24 +140,27 @@ public class ADKerberosOperationHandler extends KerberosOperationHandler {
    *
    * @param principal a String containing the principal to test
    * @return true if the principal exists; false otherwise
-   * @throws AmbariException
+   * @throws KerberosOperationException
    */
   @Override
-  public boolean principalExists(String principal) throws AmbariException {
+  public boolean principalExists(String principal) throws KerberosOperationException {
+    if (!isOpen()) {
+      throw new KerberosOperationException("This operation handler has not be opened");
+    }
     if (principal == null) {
-      throw new AmbariException("principal is null");
+      throw new KerberosOperationException("principal is null");
     }
     NamingEnumeration<SearchResult> searchResultEnum = null;
     try {
       searchResultEnum = ldapContext.search(
-        principalContainerDn,
-        "(cn=" + principal + ")",
-        searchControls);
+          principalContainerDn,
+          "(cn=" + principal + ")",
+          searchControls);
       if (searchResultEnum.hasMore()) {
         return true;
       }
     } catch (NamingException ne) {
-      throw new AmbariException("can not check if principal exists: " + principal, ne);
+      throw new KerberosOperationException("can not check if principal exists: " + principal, ne);
     } finally {
       try {
         if (searchResultEnum != null) {
@@ -221,16 +181,19 @@ public class ADKerberosOperationHandler extends KerberosOperationHandler {
    * @param principal a String containing the principal to add
    * @param password  a String containing the password to use when creating the principal
    * @return an Integer declaring the generated key number
-   * @throws AmbariException
+   * @throws KerberosOperationException
    */
   @Override
   public Integer createServicePrincipal(String principal, String password)
-    throws AmbariException {
+      throws KerberosOperationException {
+    if (!isOpen()) {
+      throw new KerberosOperationException("This operation handler has not be opened");
+    }
     if (principal == null) {
-      throw new AmbariException("principal is null");
+      throw new KerberosOperationException("principal is null");
     }
     if (password == null) {
-      throw new AmbariException("principal password is null");
+      throw new KerberosOperationException("principal password is null");
     }
     Attributes attributes = new BasicAttributes();
 
@@ -243,7 +206,7 @@ public class ADKerberosOperationHandler extends KerberosOperationHandler {
     attributes.put(cn);
 
     Attribute upn = new BasicAttribute("userPrincipalName");
-    upn.add(principal + "@" + realm.toLowerCase());
+    upn.add(String.format("%s@%s", principal, getDefaultRealm().toLowerCase()));
     attributes.put(upn);
 
     Attribute spn = new BasicAttribute("servicePrincipalName");
@@ -259,7 +222,7 @@ public class ADKerberosOperationHandler extends KerberosOperationHandler {
     try {
       passwordAttr.add(quotedPasswordVal.getBytes("UTF-16LE"));
     } catch (UnsupportedEncodingException ue) {
-      throw new AmbariException("Can not encode password with UTF-16LE", ue);
+      throw new KerberosOperationException("Can not encode password with UTF-16LE", ue);
     }
     attributes.put(passwordAttr);
 
@@ -267,7 +230,7 @@ public class ADKerberosOperationHandler extends KerberosOperationHandler {
       Name name = new CompositeName().add("cn=" + principal + "," + principalContainerDn);
       ldapContext.createSubcontext(name, attributes);
     } catch (NamingException ne) {
-      throw new AmbariException("Can not created principal : " + principal, ne);
+      throw new KerberosOperationException("Can not create principal : " + principal, ne);
     }
     return 0;
   }
@@ -280,35 +243,38 @@ public class ADKerberosOperationHandler extends KerberosOperationHandler {
    * @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 AmbariException
+   * @throws KerberosOperationException
    */
   @Override
-  public Integer setPrincipalPassword(String principal, String password) throws AmbariException {
+  public Integer setPrincipalPassword(String principal, String password) throws KerberosOperationException {
+    if (!isOpen()) {
+      throw new KerberosOperationException("This operation handler has not be opened");
+    }
     if (principal == null) {
-      throw new AmbariException("principal is null");
+      throw new KerberosOperationException("principal is null");
     }
     if (password == null) {
-      throw new AmbariException("principal password is null");
+      throw new KerberosOperationException("principal password is null");
     }
-    if (!principalExists(principal)) {
-      if (password == null) {
-        throw new AmbariException("principal not found : " + principal);
+    try {
+      if (!principalExists(principal)) {
+        throw new KerberosOperationException("principal not found : " + principal);
       }
+    } catch (KerberosOperationException e) {
+      e.printStackTrace();
     }
     try {
-      createLdapContext();
-
       ModificationItem[] mods = new ModificationItem[1];
       String quotedPasswordVal = "\"" + password + "\"";
       mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,
-        new BasicAttribute("UnicodePwd", quotedPasswordVal.getBytes("UTF-16LE")));
+          new BasicAttribute("UnicodePwd", quotedPasswordVal.getBytes("UTF-16LE")));
       ldapContext.modifyAttributes(
-        new CompositeName().add("cn=" + principal + "," + principalContainerDn),
-        mods);
+          new CompositeName().add("cn=" + principal + "," + principalContainerDn),
+          mods);
     } catch (NamingException ne) {
-      throw new AmbariException("Can not set password for principal : " + principal, ne);
+      throw new KerberosOperationException("Can not set password for principal : " + principal, ne);
     } catch (UnsupportedEncodingException ue) {
-      throw new AmbariException("Unsupported encoding UTF-16LE", ue);
+      throw new KerberosOperationException("Unsupported encoding UTF-16LE", ue);
     }
     return 0;
   }
@@ -320,61 +286,109 @@ public class ADKerberosOperationHandler extends KerberosOperationHandler {
    *
    * @param principal a String containing the principal to remove
    * @return true if the principal was successfully removed; otherwise false
-   * @throws AmbariException
+   * @throws KerberosOperationException
    */
   @Override
-  public boolean removeServicePrincipal(String principal) throws AmbariException {
+  public boolean removeServicePrincipal(String principal) throws KerberosOperationException {
+    if (!isOpen()) {
+      throw new KerberosOperationException("This operation handler has not be opened");
+    }
     if (principal == null) {
-      throw new AmbariException("principal is null");
+      throw new KerberosOperationException("principal is null");
     }
-    if (!principalExists(principal)) {
-      return false;
+    try {
+      if (!principalExists(principal)) {
+        return false;
+      }
+    } catch (KerberosOperationException e) {
+      e.printStackTrace();
     }
     try {
       Name name = new CompositeName().add("cn=" + principal + "," + principalContainerDn);
       ldapContext.destroySubcontext(name);
     } catch (NamingException ne) {
-      throw new AmbariException("Can not remove principal: " + principal);
+      throw new KerberosOperationException("Can not remove principal: " + principal);
     }
+
     return true;
   }
 
   /**
-   * Implementation of main method to illustrate the use of operations on this class
+   * Helper method to create the LDAP context needed to interact with the Active Directory.
    *
-   * @param args not used here
-   * @throws Throwable
+   * @return the relevant LdapContext
+   * @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
    */
-  public static void main(String[] args) throws Throwable {
-
-    // SSL Certificate of AD should have been imported into truststore when that certificate
-    // is not issued by trusted authority. This is typical with self signed certificated in
-    // development environment
-    System.setProperty("javax.net.ssl.trustStore",
-      "/tmp/workspace/ambari/apache-ambari-rd/cacerts");
-
-    ADKerberosOperationHandler handler = new ADKerberosOperationHandler();
-
-    KerberosCredential kc = new KerberosCredential(
-      "Administrator@knox.com", "hadoop", null);  // null keytab
-
-    handler.open(kc, "KNOX.COM",
-      "ldaps://dillwin12.knox.com:636", "ou=service accounts,dc=knox,dc=com");
-
-    // does the princial already exist?
-    System.out.println("Principal exists: " + handler.principalExists("nn/c1508.ambari.apache.org"));
-
-    //create principal
-    handler.createServicePrincipal("nn/c1508.ambari.apache.org", "welcome");
+  protected LdapContext createLdapContext() throws KerberosOperationException {
+    KerberosCredential administratorCredentials = getAdministratorCredentials();
+
+    Properties properties = new Properties();
+    properties.put(Context.INITIAL_CONTEXT_FACTORY, LDAP_CONTEXT_FACTORY_CLASS);
+    properties.put(Context.PROVIDER_URL, ldapUrl);
+    properties.put(Context.SECURITY_PRINCIPAL, administratorCredentials.getPrincipal());
+    properties.put(Context.SECURITY_CREDENTIALS, administratorCredentials.getPassword());
+    properties.put(Context.SECURITY_AUTHENTICATION, LDAP_ATUH_MECH_SIMPLE);
+    properties.put(Context.REFERRAL, "follow");
+    properties.put("java.naming.ldap.factory.socket", TrustingSSLSocketFactory.class.getName());
 
-    //update the password
-    handler.setPrincipalPassword("nn/c1508.ambari.apache.org", "welcome10");
-
-    // remove the principal
-    // handler.removeServicePrincipal("nn/c1508.ambari.apache.org");
+    try {
+      return createInitialLdapContext(properties, null);
+    } catch (CommunicationException e) {
+      String message = String.format("Failed to communicate with the Active Directory at %s: %s", ldapUrl, e.getMessage());
+      LOG.warn(message, e);
+      throw new KerberosKDCConnectionException(message, e);
+    } catch (AuthenticationException e) {
+      String message = String.format("Failed to authenticate with the Active Directory at %s: %s", ldapUrl, e.getMessage());
+      LOG.warn(message, e);
+      throw new KerberosAdminAuthenticationException(message, e);
+    } catch (NamingException e) {
+      String error = e.getMessage();
+
+      if ((error != null) && !error.isEmpty()) {
+        String message = String.format("Failed to communicate with the Active Directory at %s: %s", ldapUrl, e.getMessage());
+        LOG.warn(message, e);
+
+        if (error.startsWith("Cannot parse url:")) {
+          throw new KerberosKDCConnectionException(message, e);
+        } else {
+          throw new KerberosOperationException(message, e);
+        }
+      } else {
+        throw new KerberosOperationException("Unexpected error condition", e);
+      }
+    }
+  }
 
-    handler.close();
+  /**
+   * Helper method to create the LDAP context needed to interact with the Active Directory.
+   * <p/>
+   * This is mainly used to help with building mocks for test cases.
+   *
+   * @param properties environment used to create the initial DirContext.
+   *                   Null indicates an empty environment.
+   * @param controls   connection request controls for the initial context.
+   *                   If null, no connection request controls are used.
+   * @return the relevant LdapContext
+   * @throws NamingException if a naming exception is encountered
+   */
+  protected LdapContext createInitialLdapContext(Properties properties, Control[] controls)
+      throws NamingException {
+    return new InitialLdapContext(properties, controls);
+  }
 
+  /**
+   * Helper method to create the SearchControls instance
+   *
+   * @return the relevant SearchControls
+   */
+  protected SearchControls createSearchControls() {
+    SearchControls searchControls = new SearchControls();
+    searchControls.setSearchScope(ONE_LEVEL_SCOPE);
+    searchControls.setReturningAttributes(new String[]{"cn"});
+    return searchControls;
   }
 
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/efe79f01/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreateKeytabFilesServerAction.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreateKeytabFilesServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreateKeytabFilesServerAction.java
index be70ba1..6e53140 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreateKeytabFilesServerAction.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreateKeytabFilesServerAction.java
@@ -139,13 +139,19 @@ public class CreateKeytabFilesServerAction extends KerberosServerAction {
               File keytabFile = new File(hostDirectory, DigestUtils.sha1Hex(keytabFilePath));
               Integer keyNumber = principalKeyNumberMap.get(evaluatedPrincipal);
 
-              if (operationHandler.createKeytabFile(evaluatedPrincipal, password, keyNumber, keytabFile)) {
-                LOG.debug("Successfully created keytab file for {} at {}",
-                    evaluatedPrincipal, keytabFile.getAbsolutePath());
-              } else {
-                String message = String.format("Failed to create keytab file for %s at %s",
-                    evaluatedPrincipal, keytabFile.getAbsolutePath());
-                LOG.error(message);
+              try {
+                if (operationHandler.createKeytabFile(evaluatedPrincipal, password, keyNumber, keytabFile)) {
+                  LOG.debug("Successfully created keytab file for {} at {}",
+                      evaluatedPrincipal, keytabFile.getAbsolutePath());
+                } else {
+                  String message = String.format("Failed to create keytab file for %s at %s",
+                      evaluatedPrincipal, keytabFile.getAbsolutePath());
+                  LOG.error(message);
+                  commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", "", message);
+                }
+              } catch (KerberosOperationException e) {
+                String message = String.format("Failed to create keytab file for %s - %s", evaluatedPrincipal, e.getMessage());
+                LOG.error(message, e);
                 commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", "", message);
               }
             } else {

http://git-wip-us.apache.org/repos/asf/ambari/blob/efe79f01/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreatePrincipalsServerAction.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreatePrincipalsServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreatePrincipalsServerAction.java
index a6392da..38ca320 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreatePrincipalsServerAction.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreatePrincipalsServerAction.java
@@ -95,35 +95,41 @@ public class CreatePrincipalsServerAction extends KerberosServerAction {
     if (password == null) {
       password = operationHandler.createSecurePassword();
 
-      if (operationHandler.principalExists(evaluatedPrincipal)) {
-        // Create a new password since we need to know what it is.
-        // A new password/key would have been generated after exporting the keytab anyways.
-        LOG.warn("Principal already exists, setting new password - {}", evaluatedPrincipal);
-
-        Integer keyNumber = operationHandler.setPrincipalPassword(evaluatedPrincipal, password);
-
-        if (keyNumber != null) {
-          principalPasswordMap.put(evaluatedPrincipal, password);
-          principalKeyNumberMap.put(evaluatedPrincipal, keyNumber);
-          LOG.debug("Successfully set password for principal {}", evaluatedPrincipal);
-        } else {
-          String message = String.format("Failed to set password for principal %s, unknown reason", evaluatedPrincipal);
-          LOG.error(message);
-          commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", "", message);
-        }
-      } else {
-        LOG.debug("Creating new principal - {}", evaluatedPrincipal);
-        Integer keyNumber = operationHandler.createServicePrincipal(evaluatedPrincipal, password);
-
-        if (keyNumber != null) {
-          principalPasswordMap.put(evaluatedPrincipal, password);
-          principalKeyNumberMap.put(evaluatedPrincipal, keyNumber);
-          LOG.debug("Successfully created new principal {}", evaluatedPrincipal);
+      try {
+        if (operationHandler.principalExists(evaluatedPrincipal)) {
+          // Create a new password since we need to know what it is.
+          // A new password/key would have been generated after exporting the keytab anyways.
+          LOG.warn("Principal already exists, setting new password - {}", evaluatedPrincipal);
+
+          Integer keyNumber = operationHandler.setPrincipalPassword(evaluatedPrincipal, password);
+
+          if (keyNumber != null) {
+            principalPasswordMap.put(evaluatedPrincipal, password);
+            principalKeyNumberMap.put(evaluatedPrincipal, keyNumber);
+            LOG.debug("Successfully set password for principal {}", evaluatedPrincipal);
+          } else {
+            String message = String.format("Failed to set password for principal %s - unknown reason", evaluatedPrincipal);
+            LOG.error(message);
+            commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", "", message);
+          }
         } else {
-          String message = String.format("Failed to create principal %s, unknown reason", evaluatedPrincipal);
-          LOG.error(message);
-          commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", "", message);
+          LOG.debug("Creating new principal - {}", evaluatedPrincipal);
+          Integer keyNumber = operationHandler.createServicePrincipal(evaluatedPrincipal, password);
+
+          if (keyNumber != null) {
+            principalPasswordMap.put(evaluatedPrincipal, password);
+            principalKeyNumberMap.put(evaluatedPrincipal, keyNumber);
+            LOG.debug("Successfully created new principal {}", evaluatedPrincipal);
+          } else {
+            String message = String.format("Failed to create principal %s - unknown reason", evaluatedPrincipal);
+            LOG.error(message);
+            commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", "", message);
+          }
         }
+      } catch (KerberosOperationException e) {
+        String message = String.format("Failed to create principal %s - %s", evaluatedPrincipal, e.getMessage());
+        LOG.error(message, e);
+        commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", "", message);
       }
     }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/efe79f01/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 ae2d4b2..5a1310d 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
@@ -18,7 +18,6 @@
 
 package org.apache.ambari.server.serveraction.kerberos;
 
-import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.utils.ShellCommandUtil;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.directory.server.kerberos.shared.crypto.encryption.KerberosKeyFactory;
@@ -77,9 +76,9 @@ public abstract class KerberosOperationHandler {
         add(EncryptionType.AES256_CTS_HMAC_SHA1_96);
       }});
 
-  private KerberosCredential administratorCredentials;
-  private String defaultRealm;
-
+  private KerberosCredential administratorCredentials = null;
+  private String defaultRealm = null;
+  private boolean open = false;
 
   /**
    * Create a secure (random) password using a secure random number generator and a set of (reasonable)
@@ -121,38 +120,36 @@ public abstract class KerberosOperationHandler {
   }
 
   /**
-     * Prepares and creates resources to be used by this KerberosOperationHandler
-     * <p/>
-     * It is expected that this KerberosOperationHandler will not be used before this call.
-     *
-     * @param administratorCredentials a KerberosCredential containing the administrative credentials
-     *                                 for the relevant KDC
-     * @param defaultRealm             a String declaring the default Kerberos realm (or domain)
-     */
-    public abstract void open(KerberosCredential administratorCredentials, String defaultRealm)
-            throws AmbariException;
-
-    /**
-     * Prepares and creates resources to be used by this KerberosOperationHandler.
-     * Implementation in this class is ignoring parameters ldapUrl and principalContainerDn and delegate to
-     * <code>open(KerberosCredential administratorCredentials, String defaultRealm)</code>
-     * Subclasses that want to use these parameters need to override this method.
-     *
-     * <p/>
-     * It is expected that this KerberosOperationHandler will not be used before this call.
-     *
-     * @param administratorCredentials a KerberosCredential containing the administrative credentials
-     *                                 for the relevant KDC
-     * @param defaultRealm             a String declaring the default Kerberos realm (or domain)
-     * @param ldapUrl  ldapUrl of ldap back end where principals would be created
-     * @param principalContainerDn DN of the container in ldap back end where principals would be created
-     *
-     */
-    public void open(KerberosCredential administratorCredentials, String defaultRealm,
-                              String ldapUrl, String principalContainerDn)
-            throws AmbariException {
-       open(administratorCredentials, defaultRealm);
-    }
+   * Prepares and creates resources to be used by this KerberosOperationHandler
+   * <p/>
+   * It is expected that this KerberosOperationHandler will not be used before this call.
+   *
+   * @param administratorCredentials a KerberosCredential containing the administrative credentials
+   *                                 for the relevant KDC
+   * @param defaultRealm             a String declaring the default Kerberos realm (or domain)
+   */
+  public abstract void open(KerberosCredential administratorCredentials, String defaultRealm)
+      throws KerberosOperationException;
+
+  /**
+   * Prepares and creates resources to be used by this KerberosOperationHandler.
+   * Implementation in this class is ignoring parameters ldapUrl and principalContainerDn and delegate to
+   * <code>open(KerberosCredential administratorCredentials, String defaultRealm)</code>
+   * Subclasses that want to use these parameters need to override this method.
+   * <p/>
+   * It is expected that this KerberosOperationHandler will not be used before this call.
+   *
+   * @param administratorCredentials a KerberosCredential containing the administrative credentials
+   *                                 for the relevant KDC
+   * @param defaultRealm             a String declaring the default Kerberos realm (or domain)
+   * @param ldapUrl                  ldapUrl of ldap back end where principals would be created
+   * @param principalContainerDn     DN of the container in ldap back end where principals would be created
+   */
+  public void open(KerberosCredential administratorCredentials, String defaultRealm,
+                   String ldapUrl, String principalContainerDn)
+      throws KerberosOperationException {
+    open(administratorCredentials, defaultRealm);
+  }
 
   /**
    * Closes and cleans up any resources used by this KerberosOperationHandler
@@ -160,7 +157,7 @@ public abstract class KerberosOperationHandler {
    * It is expected that this KerberosOperationHandler will not be used after this call.
    */
   public abstract void close()
-      throws AmbariException;
+      throws KerberosOperationException;
 
   /**
    * Test to see if the specified principal exists in a previously configured KDC
@@ -169,10 +166,10 @@ public abstract class KerberosOperationHandler {
    *
    * @param principal a String containing the principal to test
    * @return true if the principal exists; false otherwise
-   * @throws AmbariException
+   * @throws KerberosOperationException
    */
   public abstract boolean principalExists(String principal)
-      throws AmbariException;
+      throws KerberosOperationException;
 
   /**
    * Creates a new principal in a previously configured KDC
@@ -182,10 +179,10 @@ public abstract class KerberosOperationHandler {
    * @param principal a String containing the principal to add
    * @param password  a String containing the password to use when creating the principal
    * @return an Integer declaring the generated key number
-   * @throws AmbariException
+   * @throws KerberosOperationException
    */
   public abstract Integer createServicePrincipal(String principal, String password)
-      throws AmbariException;
+      throws KerberosOperationException;
 
   /**
    * Updates the password for an existing principal in a previously configured KDC
@@ -195,10 +192,10 @@ public abstract class KerberosOperationHandler {
    * @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 AmbariException
+   * @throws KerberosOperationException
    */
   public abstract Integer setPrincipalPassword(String principal, String password)
-      throws AmbariException;
+      throws KerberosOperationException;
 
   /**
    * Removes an existing principal in a previously configured KDC
@@ -207,10 +204,27 @@ public abstract class KerberosOperationHandler {
    *
    * @param principal a String containing the principal to remove
    * @return true if the principal was successfully removed; otherwise false
-   * @throws AmbariException
+   * @throws KerberosOperationException
    */
   public abstract boolean removeServicePrincipal(String principal)
-      throws AmbariException;
+      throws KerberosOperationException;
+
+  /**
+   * Tests to ensure the connection information and credentials allow for administrative
+   * connectivity to the KDC
+   *
+   * @return true of successful; otherwise false
+   * @throws KerberosOperationException if a failure occurs while testing the
+   *                                    administrator credentials
+   */
+  public boolean testAdministratorCredentials() throws KerberosOperationException {
+    KerberosCredential credentials = getAdministratorCredentials();
+    if (credentials == null) {
+      throw new KerberosOperationException("Missing KDC administrator credentials");
+    } else {
+      return principalExists(credentials.getPrincipal());
+    }
+  }
 
   /**
    * Create or append to a keytab file using the specified principal and password.
@@ -219,18 +233,18 @@ public abstract class KerberosOperationHandler {
    * @param password   a String containing the password to use when creating the principal
    * @param keytabFile a File containing the absolute path to the keytab file
    * @return true if the keytab file was successfully created; false otherwise
-   * @throws AmbariException
+   * @throws KerberosOperationException
    */
   public boolean createKeytabFile(String principal, String password, Integer keyNumber, File keytabFile)
-      throws AmbariException {
+      throws KerberosOperationException {
     boolean success = false;
 
     if ((principal == null) || principal.isEmpty()) {
-      throw new AmbariException("Failed to create keytab file, missing principal");
+      throw new KerberosOperationException("Failed to create keytab file, missing principal");
     } else if (password == null) {
-      throw new AmbariException(String.format("Failed to create keytab file for %s, missing password", principal));
+      throw new KerberosOperationException(String.format("Failed to create keytab file for %s, missing password", principal));
     } else if (keytabFile == null) {
-      throw new AmbariException(String.format("Failed to create keytab file for %s, missing file path", principal));
+      throw new KerberosOperationException(String.format("Failed to create keytab file for %s, missing file path", principal));
     } else {
       Keytab keytab;
       Set<EncryptionType> ciphers = new HashSet<EncryptionType>(DEFAULT_CIPHERS);
@@ -294,7 +308,7 @@ public abstract class KerberosOperationHandler {
               keytabFile.deleteOnExit();
             }
 
-            throw new AmbariException(message, e);
+            throw new KerberosOperationException(message, e);
           }
         }
       }
@@ -320,6 +334,24 @@ public abstract class KerberosOperationHandler {
   }
 
   /**
+   * Test this KerberosOperationHandler to see whether is was previously open or not
+   *
+   * @return a boolean value indicating whether this KerberosOperationHandler was open (true) or not (false)
+   */
+  public boolean isOpen() {
+    return open;
+  }
+
+  /**
+   * Sets whether this KerberosOperationHandler is open or not.
+   *
+   * @param open a boolean value indicating whether this KerberosOperationHandler was open (true) or not (false)
+   */
+  public void setOpen(boolean open) {
+    this.open = open;
+  }
+
+  /**
    * Given base64-encoded keytab data, decode the String to binary data and write it to a (temporary)
    * file.
    * <p/>
@@ -328,10 +360,10 @@ public abstract class KerberosOperationHandler {
    *
    * @param keytabData a String containing base64-encoded keytab data
    * @return a File pointing to the decoded keytab file or null if not successful
-   * @throws AmbariException
+   * @throws KerberosOperationException
    */
   protected File createKeytabFile(String keytabData)
-      throws AmbariException {
+      throws KerberosOperationException {
     boolean success = false;
     File tempFile = null;
 
@@ -354,12 +386,12 @@ public abstract class KerberosOperationHandler {
         String message = String.format("Failed to write to temporary keytab file %s: %s",
             tempFile.getAbsolutePath(), e.getLocalizedMessage());
         LOG.error(message, e);
-        throw new AmbariException(message, e);
+        throw new KerberosOperationException(message, e);
       } catch (IOException e) {
         String message = String.format("Failed to write to temporary keytab file %s: %s",
             tempFile.getAbsolutePath(), e.getLocalizedMessage());
         LOG.error(message, e);
-        throw new AmbariException(message, e);
+        throw new KerberosOperationException(message, e);
       } finally {
         if (fos != null) {
           try {
@@ -390,10 +422,10 @@ public abstract class KerberosOperationHandler {
    *
    * @param command an array of String value representing the command and its arguments
    * @return a ShellCommandUtil.Result declaring the result of the operation
-   * @throws AmbariException
+   * @throws KerberosOperationException
    */
   protected ShellCommandUtil.Result executeCommand(String[] command)
-      throws AmbariException {
+      throws KerberosOperationException {
 
     if ((command == null) || (command.length == 0)) {
       return null;
@@ -403,11 +435,11 @@ public abstract class KerberosOperationHandler {
       } catch (IOException e) {
         String message = String.format("Failed to execute the command: %s", e.getLocalizedMessage());
         LOG.error(message, e);
-        throw new AmbariException(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 AmbariException(message, e);
+        throw new KerberosOperationException(message, e);
       }
     }
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/efe79f01/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosOperationHandlerFactory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosOperationHandlerFactory.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosOperationHandlerFactory.java
index 30e3c35..a717b90 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosOperationHandlerFactory.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosOperationHandlerFactory.java
@@ -18,9 +18,12 @@
 
 package org.apache.ambari.server.serveraction.kerberos;
 
+import com.google.inject.Singleton;
+
 /**
  * KerberosOperationHandlerFactory gets relevant KerberosOperationHandlers given a KDCType.
  */
+@Singleton
 public class KerberosOperationHandlerFactory {
 
   /**
@@ -32,7 +35,7 @@ public class KerberosOperationHandlerFactory {
    * @param kdcType the relevant KDCType
    * @return a KerberosOperationHandler
    */
-  public static KerberosOperationHandler getKerberosOperationHandler(KDCType kdcType) {
+  public KerberosOperationHandler getKerberosOperationHandler(KDCType kdcType) {
     KerberosOperationHandler handler = null;
 
     // If not specified, use KDCType.MIT_KDC as a default
@@ -48,7 +51,6 @@ public class KerberosOperationHandlerFactory {
       case ACTIVE_DIRECTORY:
         handler = new ADKerberosOperationHandler();
         break;
-
     }
 
     return handler;

http://git-wip-us.apache.org/repos/asf/ambari/blob/efe79f01/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 a99628c..2f91826 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
@@ -97,6 +97,15 @@ public abstract class KerberosServerAction extends AbstractServerAction {
   private Clusters clusters = null;
 
   /**
+   * The KerberosOperationHandlerFactory to use to obtain KerberosOperationHandler instances
+   * <p/>
+   * This is needed to help with test cases to mock a KerberosOperationHandler
+   */
+  @Inject
+  private KerberosOperationHandlerFactory kerberosOperationHandlerFactory;
+
+
+  /**
    * Given a (command parameter) Map and a property name, attempts to safely retrieve the requested
    * data.
    *
@@ -301,7 +310,7 @@ public abstract class KerberosServerAction extends AbstractServerAction {
               throw new AmbariException(message);
             }
 
-            KerberosOperationHandler handler = KerberosOperationHandlerFactory.getKerberosOperationHandler(kdcType);
+            KerberosOperationHandler handler = kerberosOperationHandlerFactory.getKerberosOperationHandler(kdcType);
             if (handler == null) {
               String message = String.format("Failed to process the identities, a KDC operation handler was not found for the KDC type of : %s",
                   kdcType.toString());
@@ -325,9 +334,7 @@ public abstract class KerberosServerAction extends AbstractServerAction {
                   break;
                 }
               }
-            } catch (AmbariException e) {
-              // Catch this separately from IOException since the reason it was thrown was not the same
-              // Note: AmbariException is an IOException, so there may be some confusion
+            } catch (KerberosOperationException e) {
               throw new AmbariException(e.getMessage(), e);
             } catch (IOException e) {
               String message = String.format("Failed to process the identities, cannot read the index file: %s",
@@ -349,7 +356,7 @@ public abstract class KerberosServerAction extends AbstractServerAction {
               // exception since there is little we can or care to do about it now.
               try {
                 handler.close();
-              } catch (AmbariException e) {
+              } catch (KerberosOperationException e) {
                 // Ignore this...
               }
             }

http://git-wip-us.apache.org/repos/asf/ambari/blob/efe79f01/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 04d43a5..a70b412 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,7 +18,6 @@
 
 package org.apache.ambari.server.serveraction.kerberos;
 
-import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.utils.ShellCommandUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -50,14 +49,16 @@ public class MITKerberosOperationHandler extends KerberosOperationHandler {
 
 
   @Override
-  public void open(KerberosCredential administratorCredentials, String defaultRealm) throws AmbariException {
+  public void open(KerberosCredential administratorCredentials, String defaultRealm) throws KerberosOperationException {
     setAdministratorCredentials(administratorCredentials);
     setDefaultRealm(defaultRealm);
+    setOpen(true);
   }
 
   @Override
-  public void close() throws AmbariException {
+  public void close() throws KerberosOperationException {
     // There is nothing to do here.
+    setOpen(false);
   }
 
   /**
@@ -68,11 +69,18 @@ public class MITKerberosOperationHandler extends KerberosOperationHandler {
    *
    * @param principal a String containing the principal to test
    * @return true if the principal exists; false otherwise
-   * @throws AmbariException
+   * @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
    */
   @Override
   public boolean principalExists(String principal)
-      throws AmbariException {
+      throws KerberosOperationException {
+
+    if (!isOpen()) {
+      throw new KerberosOperationException("This operation handler has not be opened");
+    }
 
     if (principal == null) {
       return false;
@@ -80,30 +88,18 @@ public class MITKerberosOperationHandler extends KerberosOperationHandler {
       // Create the KAdmin query to execute:
       String query = String.format("get_principal %s", principal);
 
+      ShellCommandUtil.Result result;
       try {
-        ShellCommandUtil.Result result = invokeKAdmin(query);
-
-        if (result != null) {
-          if (result.isSuccessful()) {
-            String stdOut = result.getStdout();
-
-            // If there is data from STDOUT, see if the following string exists:
-            //    Principal: <principal>
-            return (stdOut != null) && stdOut.contains(String.format("Principal: %s", principal));
-          } else {
-            LOG.warn("Failed to query for principal {}:\n\tExitCode: {}\n\tSTDOUT: {}\n\tSTDERR: {}",
-                principal, result.getExitCode(), result.getStdout(), result.getStderr());
-            throw new AmbariException(String.format("Failed to query for principal %s", principal));
-          }
-        } else {
-          String message = String.format("Failed to query for principal %s - Unknown reason", principal);
-          LOG.warn(message);
-          throw new AmbariException(message);
-        }
-      } catch (AmbariException e) {
+        result = invokeKAdmin(query);
+      } catch (KerberosOperationException e) {
         LOG.error(String.format("Failed to query for principal %s", principal), e);
         throw e;
       }
+
+      // 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));
     }
   }
 
@@ -117,60 +113,41 @@ public class MITKerberosOperationHandler extends KerberosOperationHandler {
    * @param principal a String containing the principal add
    * @param password  a String containing the password to use when creating the principal
    * @return an Integer declaring the generated key number
-   * @throws AmbariException
+   * @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
    */
   @Override
   public Integer createServicePrincipal(String principal, String password)
-      throws AmbariException {
+      throws KerberosOperationException {
+
+    if (!isOpen()) {
+      throw new KerberosOperationException("This operation handler has not be opened");
+    }
 
     if ((principal == null) || principal.isEmpty()) {
-      throw new AmbariException("Failed to create new principal - no principal specified");
+      throw new KerberosOperationException("Failed to create new principal - no principal specified");
+    } else if ((password == null) || password.isEmpty()) {
+      throw new KerberosOperationException("Failed to create new principal - no password specified");
     } else {
       // Create the kdamin query:  add_principal <-randkey|-pw <password>> <principal>
-      StringBuilder queryBuilder = new StringBuilder();
-
-      queryBuilder.append("add_principal");
-
-      // If a password was not supplied, have the KDC generate a random key, else use the supplied
-      // password
-      if ((password == null) || password.isEmpty()) {
-        queryBuilder.append(" -randkey");
-      } else {
-        queryBuilder.append(" -pw ");
-        queryBuilder.append(password);
-      }
-
-      queryBuilder.append(" ");
-      queryBuilder.append(principal);
-
+      ShellCommandUtil.Result result;
       try {
-        ShellCommandUtil.Result result = invokeKAdmin(queryBuilder.toString());
-
-        if (result != null) {
-          if (result.isSuccessful()) {
-            String stdOut = result.getStdout();
-
-            // If there is data from STDOUT, see if the following string exists:
-            //    Principal "<principal>" created
-            if ((stdOut != null) && stdOut.contains(String.format("Principal \"%s\" created", principal))) {
-              return getKeyNumber(principal);
-            } else {
-              throw new AmbariException(String.format("Failed to create service principal for %s", principal));
-            }
-          } else {
-            LOG.warn("Failed to create service principal for {}:\n\tExitCode: {}\n\tSTDOUT: {}\n\tSTDERR: {}",
-                principal, result.getExitCode(), result.getStdout(), result.getStderr());
-            throw new AmbariException(String.format("Failed to create service principal for %s", principal));
-          }
-        } else {
-          String message = String.format("Failed to create service principal for %s - Unknown reason", principal);
-          LOG.warn(message);
-          throw new AmbariException(message);
-        }
-      } catch (AmbariException e) {
+        result = invokeKAdmin(String.format("add_principal -pw %s %s", password, principal));
+      } catch (KerberosOperationException e) {
         LOG.error(String.format("Failed to create new principal for %s", principal), e);
         throw e;
       }
+
+      // If there is data from STDOUT, see if the following string exists:
+      //    Principal "<principal>" created
+      String stdOut = result.getStdout();
+      if ((stdOut != null) && stdOut.contains(String.format("Principal \"%s\" created", principal))) {
+        return getKeyNumber(principal);
+      } else {
+        throw new KerberosOperationException(String.format("Failed to create service principal for %s", principal));
+      }
     }
   }
 
@@ -183,50 +160,31 @@ public class MITKerberosOperationHandler extends KerberosOperationHandler {
    * @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 AmbariException
+   * @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
    */
   @Override
-  public Integer setPrincipalPassword(String principal, String password) throws AmbariException {
+  public Integer setPrincipalPassword(String principal, String password) throws KerberosOperationException {
+    if (!isOpen()) {
+      throw new KerberosOperationException("This operation handler has not be opened");
+    }
+
     if ((principal == null) || principal.isEmpty()) {
-      throw new AmbariException("Failed to set password - no principal specified");
+      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 {
       // Create the kdamin query:  change_password <-randkey|-pw <password>> <principal>
-      StringBuilder queryBuilder = new StringBuilder();
-
-      queryBuilder.append("change_password");
-
-      // If a password was not supplied, have the KDC generate a random key, else use the supplied
-      // password
-      if ((password == null) || password.isEmpty()) {
-        queryBuilder.append(" -randkey");
-      } else {
-        queryBuilder.append(" -pw ");
-        queryBuilder.append(password);
-      }
-
-      queryBuilder.append(" ");
-      queryBuilder.append(principal);
-
       try {
-        ShellCommandUtil.Result result = invokeKAdmin(queryBuilder.toString());
-
-        if (result != null) {
-          if (result.isSuccessful()) {
-            return getKeyNumber(principal);
-          } else {
-            LOG.warn("Failed to set password for {}:\n\tExitCode: {}\n\tSTDOUT: {}\n\tSTDERR: {}",
-                principal, result.getExitCode(), result.getStdout(), result.getStderr());
-            throw new AmbariException(String.format("Failed to update password for %s", principal));
-          }
-        } else {
-          String message = String.format("Failed to set password for %s - Unknown reason", principal);
-          LOG.warn(message);
-          throw new AmbariException(message);
-        }
-      } catch (AmbariException e) {
+        invokeKAdmin(String.format("change_password -pw %s %s", password, principal));
+      } catch (KerberosOperationException e) {
         LOG.error(String.format("Failed to set password for %s", principal), e);
         throw e;
       }
+
+      return getKeyNumber(principal);
     }
   }
 
@@ -237,37 +195,33 @@ public class MITKerberosOperationHandler extends KerberosOperationHandler {
    *
    * @param principal a String containing the principal to remove
    * @return true if the principal was successfully removed; otherwise false
-   * @throws AmbariException
+   * @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
    */
   @Override
-  public boolean removeServicePrincipal(String principal) throws AmbariException {
+  public boolean removeServicePrincipal(String principal) throws KerberosOperationException {
+    if (!isOpen()) {
+      throw new KerberosOperationException("This operation handler has not be opened");
+    }
+
     if ((principal == null) || principal.isEmpty()) {
-      throw new AmbariException("Failed to remove new principal - no principal specified");
+      throw new KerberosOperationException("Failed to remove new principal - no principal specified");
     } else {
+      ShellCommandUtil.Result result;
+
       try {
-        ShellCommandUtil.Result result = invokeKAdmin(String.format("delete_principal -force %s", principal));
-
-        if (result != null) {
-          if (result.isSuccessful()) {
-            String stdOut = result.getStdout();
-
-            // If there is data from STDOUT, see if the following string exists:
-            //    Principal "<principal>" created
-            return (stdOut != null) && !stdOut.contains("Principal does not exist");
-          } else {
-            LOG.warn("Failed to remove service principal for {}:\n\tExitCode: {}\n\tSTDOUT: {}\n\tSTDERR: {}",
-                principal, result.getExitCode(), result.getStdout(), result.getStderr());
-            throw new AmbariException(String.format("Failed to remove service principal for %s", principal));
-          }
-        } else {
-          String message = String.format("Failed to remove service principal for %s - Unknown reason", principal);
-          LOG.warn(message);
-          throw new AmbariException(message);
-        }
-      } catch (AmbariException e) {
+        result = invokeKAdmin(String.format("delete_principal -force %s", principal));
+      } catch (KerberosOperationException e) {
         LOG.error(String.format("Failed to remove new principal for %s", principal), e);
         throw e;
       }
+
+      // 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");
     }
   }
 
@@ -276,62 +230,59 @@ public class MITKerberosOperationHandler extends KerberosOperationHandler {
    *
    * @param principal a String declaring the principal to look up
    * @return an Integer declaring the current key number
-   * @throws AmbariException if an error occurs while looking up the relevant 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 AmbariException {
+  private Integer getKeyNumber(String principal) throws KerberosOperationException {
+    if (!isOpen()) {
+      throw new KerberosOperationException("This operation handler has not be opened");
+    }
+
     if ((principal == null) || principal.isEmpty()) {
-      throw new AmbariException("Failed to get key number for principal  - no principal specified");
+      throw new KerberosOperationException("Failed to get key number for principal  - no principal specified");
     } else {
       // Create the kdamin query:  get_principal <principal>
       String query = String.format("get_principal %s", principal);
 
+      ShellCommandUtil.Result result;
       try {
-        ShellCommandUtil.Result result = invokeKAdmin(query);
-
-        if (result != null) {
-          if (result.isSuccessful()) {
-            String stdOut = result.getStdout();
-
-            if (stdOut == null) {
-              LOG.warn("Failed to get key number for {}:\n\tExitCode: {}\n\tSTDOUT: NULL\n\tSTDERR: {}",
-                  principal, result.getExitCode(), result.getStderr());
-              throw new AmbariException(String.format("Failed to get key number for %s", principal));
-            }
-
-            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) {
-                LOG.warn("Failed to get key number for {} - invalid key number value ({}):\n\tExitCode: {}\n\tSTDOUT: NULL\n\tSTDERR: {}",
-                    principal, keyNumber, result.getExitCode(), result.getStderr());
-                throw new AmbariException(String.format("Failed to get key number for %s", principal));
-              }
-            } else {
-              LOG.warn("Failed to get key number for {} - unexpected STDOUT data:\n\tExitCode: {}\n\tSTDOUT: NULL\n\tSTDERR: {}",
-                  principal, result.getExitCode(), result.getStderr());
-              throw new AmbariException(String.format("Failed to get key number for %s", principal));
-            }
-          } else {
-            LOG.warn("Failed to get key number for {}:\n\tExitCode: {}\n\tSTDOUT: {}\n\tSTDERR: {}",
-                principal, result.getExitCode(), result.getStdout(), result.getStderr());
-            throw new AmbariException(String.format("Failed to get key number for %s", principal));
-          }
-        } else {
-          String message = String.format("Failed to get key number for %s - Unknown reason", principal);
-          LOG.warn(message);
-          throw new AmbariException(message);
-        }
-      } catch (AmbariException e) {
+        result = invokeKAdmin(query);
+      } catch (KerberosOperationException e) {
         LOG.error(String.format("Failed to get key number for %s", principal), e);
         throw e;
       }
+
+      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);
+      }
     }
   }
 
@@ -340,77 +291,104 @@ public class MITKerberosOperationHandler extends KerberosOperationHandler {
    *
    * @param query a String containing the query to send to the kdamin command
    * @return a ShellCommandUtil.Result containing the result of the operation
-   * @throws AmbariException
+   * @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 ShellCommandUtil.Result invokeKAdmin(String query)
-      throws AmbariException {
+      throws KerberosOperationException {
     ShellCommandUtil.Result result = null;
 
-    if ((query != null) && !query.isEmpty()) {
-      KerberosCredential administratorCredentials = getAdministratorCredentials();
-      String defaultRealm = getDefaultRealm();
+    if ((query == null) || query.isEmpty()) {
+      throw new KerberosOperationException("Missing kadmin query");
+    }
+    KerberosCredential administratorCredentials = getAdministratorCredentials();
+    String defaultRealm = getDefaultRealm();
 
-      List<String> command = new ArrayList<String>();
-      File tempKeytabFile = null;
+    List<String> command = new ArrayList<String>();
+    File tempKeytabFile = null;
 
-      try {
-        String adminPrincipal = (administratorCredentials == null)
-            ? null
-            : administratorCredentials.getPrincipal();
+    try {
+      String adminPrincipal = (administratorCredentials == null)
+          ? null
+          : administratorCredentials.getPrincipal();
 
-        if ((adminPrincipal == null) || adminPrincipal.isEmpty()) {
-          // Set the kdamin interface to be kadmin.local
-          command.add("kadmin.local");
-        } else {
-          String adminPassword = administratorCredentials.getPassword();
-          String adminKeyTab = administratorCredentials.getKeytab();
-
-          // Set the kdamin interface to be kadmin
-          command.add("kadmin");
-
-          // Add the administrative principal
-          command.add("-p");
-          command.add(adminPrincipal);
-
-          if ((adminKeyTab != null) && !adminKeyTab.isEmpty()) {
-            tempKeytabFile = createKeytabFile(adminKeyTab);
-
-            if (tempKeytabFile != null) {
-              // Add keytab file administrative principal
-              command.add("-k");
-              command.add("-t");
-              command.add(tempKeytabFile.getAbsolutePath());
-            }
-          } else if (adminPassword != null) {
-            // Add password for administrative principal
-            command.add("-w");
-            command.add(adminPassword);
+      if ((adminPrincipal == null) || adminPrincipal.isEmpty()) {
+        // Set the kdamin interface to be kadmin.local
+        command.add("kadmin.local");
+      } else {
+        String adminPassword = administratorCredentials.getPassword();
+        String adminKeyTab = administratorCredentials.getKeytab();
+
+        // Set the kdamin interface to be kadmin
+        command.add("kadmin");
+
+        // Add the administrative principal
+        command.add("-p");
+        command.add(adminPrincipal);
+
+        if ((adminKeyTab != null) && !adminKeyTab.isEmpty()) {
+          tempKeytabFile = createKeytabFile(adminKeyTab);
+
+          if (tempKeytabFile != null) {
+            // Add keytab file administrative principal
+            command.add("-k");
+            command.add("-t");
+            command.add(tempKeytabFile.getAbsolutePath());
           }
+        } else if (adminPassword != null) {
+          // Add password for administrative principal
+          command.add("-w");
+          command.add(adminPassword);
         }
+      }
 
-        if ((defaultRealm != null) && !defaultRealm.isEmpty()) {
-          // Add default realm clause
-          command.add("-r");
-          command.add(defaultRealm);
-        }
+      if ((defaultRealm != null) && !defaultRealm.isEmpty()) {
+        // Add default realm clause
+        command.add("-r");
+        command.add(defaultRealm);
+      }
 
-        // Add kadmin query
-        command.add("-q");
-        command.add(query.replace("\"", "\\\""));
+      // Add kadmin query
+      command.add("-q");
+      command.add(query.replace("\"", "\\\""));
 
-        result = executeCommand(command.toArray(new String[command.size()]));
-      } finally {
-        // If a temporary keytab file was created, clean it up.
-        if (tempKeytabFile != null) {
-          if (!tempKeytabFile.delete()) {
-            tempKeytabFile.deleteOnExit();
-          }
+      result = executeCommand(command.toArray(new String[command.size()]));
+
+      if (!result.isSuccessful()) {
+        String message = String.format("Failed to execute kadmin:\n\tExitCode: %s\n\tSTDOUT: %s\n\tSTDERR: %s",
+            result.getExitCode(), result.getStdout(), result.getStderr());
+        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);
+        } else if (stdErr.contains("Incorrect password while initializing")) {
+          throw new KerberosAdminAuthenticationException(stdErr);
+        }
+        // Did we fail to connect to the KDC?
+        else if (stdErr.contains("Cannot contact any KDC")) {
+          throw new KerberosKDCConnectionException(stdErr);
+        }
+        // Was the realm invalid?
+        else if (stdErr.contains("Missing parameters in krb5.conf required for kadmin client")) {
+          throw new KerberosRealmException(stdErr);
+        } else {
+          throw new KerberosOperationException("Unexpected error condition executing the kadmin command");
+        }
+      }
+    } finally {
+      // If a temporary keytab file was created, clean it up.
+      if (tempKeytabFile != null) {
+        if (!tempKeytabFile.delete()) {
+          tempKeytabFile.deleteOnExit();
         }
       }
     }
 
     return result;
   }
-
-
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/efe79f01/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 8f39f21..dea5d61 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
@@ -21,6 +21,7 @@ package org.apache.ambari.server.controller;
 import com.google.inject.AbstractModule;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
+import junit.framework.Assert;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.actionmanager.ActionManager;
 import org.apache.ambari.server.actionmanager.HostRoleCommand;
@@ -32,7 +33,12 @@ import org.apache.ambari.server.controller.internal.RequestStageContainer;
 import org.apache.ambari.server.metadata.RoleCommandOrder;
 import org.apache.ambari.server.orm.DBAccessor;
 import org.apache.ambari.server.security.SecurityHelper;
+import org.apache.ambari.server.serveraction.kerberos.KDCType;
 import org.apache.ambari.server.serveraction.kerberos.KerberosCredential;
+import org.apache.ambari.server.serveraction.kerberos.KerberosOperationException;
+import org.apache.ambari.server.serveraction.kerberos.KerberosOperationHandler;
+import org.apache.ambari.server.serveraction.kerberos.KerberosOperationHandlerTest;
+import org.apache.ambari.server.serveraction.kerberos.KerberosOperationHandlerFactory;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.Config;
@@ -77,6 +83,43 @@ public class KerberosHelperTest extends EasyMockSupport {
 
   @Before
   public void setUp() throws Exception {
+    final KerberosOperationHandlerFactory kerberosOperationHandlerFactory = createNiceMock(KerberosOperationHandlerFactory.class);
+
+    expect(kerberosOperationHandlerFactory.getKerberosOperationHandler(KDCType.MIT_KDC))
+        .andReturn(new KerberosOperationHandler() {
+          @Override
+          public void open(KerberosCredential administratorCredentials, String defaultRealm) throws KerberosOperationException {
+            setAdministratorCredentials(administratorCredentials);
+            setDefaultRealm(defaultRealm);
+          }
+
+          @Override
+          public void close() throws KerberosOperationException {
+
+          }
+
+          @Override
+          public boolean principalExists(String principal) throws KerberosOperationException {
+            return "principal".equals(principal);
+          }
+
+          @Override
+          public Integer createServicePrincipal(String principal, String password) throws KerberosOperationException {
+            return null;
+          }
+
+          @Override
+          public Integer setPrincipalPassword(String principal, String password) throws KerberosOperationException {
+            return null;
+          }
+
+          @Override
+          public boolean removeServicePrincipal(String principal) throws KerberosOperationException {
+            return false;
+          }
+        })
+        .anyTimes();
+
     injector = Guice.createInjector(new AbstractModule() {
 
       @Override
@@ -96,6 +139,7 @@ public class KerberosHelperTest extends EasyMockSupport {
         bind(StageFactory.class).toInstance(createNiceMock(StageFactory.class));
         bind(Clusters.class).toInstance(createNiceMock(ClustersImpl.class));
         bind(ConfigHelper.class).toInstance(createNiceMock(ConfigHelper.class));
+        bind(KerberosOperationHandlerFactory.class).toInstance(kerberosOperationHandlerFactory);
       }
     });
   }
@@ -141,6 +185,32 @@ public class KerberosHelperTest extends EasyMockSupport {
 
   @Test
   public void testEnableKerberos() throws Exception {
+    testEnableKerberos(new KerberosCredential("principal", "password", "keytab"));
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void testEnableKerberosMissingCredentials() throws Exception {
+    try {
+      testEnableKerberos(null);
+    }
+    catch (IllegalArgumentException e) {
+      Assert.assertTrue(e.getMessage().startsWith("Missing KDC administrator credentials"));
+      throw e;
+    }
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void testEnableKerberosInvalidCredentials() throws Exception {
+    try {
+      testEnableKerberos(new KerberosCredential("invalid_principal", "password", "keytab"));
+    }
+    catch (IllegalArgumentException e) {
+      Assert.assertTrue(e.getMessage().startsWith("Invalid KDC administrator credentials"));
+      throw e;
+    }
+  }
+
+  private void testEnableKerberos(final KerberosCredential kerberosCredential) throws Exception {
     KerberosHelper kerberosHelper = injector.getInstance(KerberosHelper.class);
 
     final ServiceComponentHost sch1 = createNiceMock(ServiceComponentHost.class);
@@ -214,9 +284,11 @@ public class KerberosHelperTest extends EasyMockSupport {
         .andReturn(new StackId("HDP", "2.2"))
         .anyTimes();
     expect(cluster.getSessionAttributes()).andReturn(new HashMap<String, Object>(){{
-      put("kerberos_admin/" + KerberosCredential.KEY_NAME_PRINCIPAL, "principal");
-      put("kerberos_admin/" + KerberosCredential.KEY_NAME_PASSWORD, "password");
-      put("kerberos_admin/" + KerberosCredential.KEY_NAME_KEYTAB, "keytab");
+      if(kerberosCredential != null) {
+        put("kerberos_admin/" + KerberosCredential.KEY_NAME_PRINCIPAL, kerberosCredential.getPrincipal());
+        put("kerberos_admin/" + KerberosCredential.KEY_NAME_PASSWORD, kerberosCredential.getPassword());
+        put("kerberos_admin/" + KerberosCredential.KEY_NAME_KEYTAB, kerberosCredential.getKeytab());
+      }
     }}).anyTimes();
 
     final Clusters clusters = injector.getInstance(Clusters.class);