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);