You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by mr...@apache.org on 2017/11/27 23:29:23 UTC
[11/30] ambari git commit: Merge trunk with feature branch and fix
some UT compilation issues (mradhakrishnan)
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/IPAKerberosOperationHandler.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/IPAKerberosOperationHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/IPAKerberosOperationHandler.java
index 9a6a07e..c411237 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/IPAKerberosOperationHandler.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/IPAKerberosOperationHandler.java
@@ -18,32 +18,14 @@
package org.apache.ambari.server.serveraction.kerberos;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.nio.charset.StandardCharsets;
-import java.text.NumberFormat;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
import java.util.Map;
-import java.util.StringTokenizer;
-import java.util.TimeZone;
-import java.util.UUID;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import java.util.Set;
import org.apache.ambari.server.security.credential.PrincipalKeyCredential;
-import org.apache.ambari.server.utils.Closeables;
import org.apache.ambari.server.utils.ShellCommandUtil;
+import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
-import org.apache.directory.server.kerberos.shared.keytab.Keytab;
+import org.apache.directory.shared.kerberos.codec.types.EncryptionType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -54,12 +36,9 @@ import org.slf4j.LoggerFactory;
* It is assumed that the IPA admin tools are installed and that the ipa shell command is
* available
*/
-public class IPAKerberosOperationHandler extends KerberosOperationHandler {
+public class IPAKerberosOperationHandler extends KDCKerberosOperationHandler {
private final static Logger LOG = LoggerFactory.getLogger(IPAKerberosOperationHandler.class);
- private String adminServerHost = null;
-
- private HashMap<String, Keytab> cachedKeytabs = null;
/**
* This is where user principals are members of. Important as the password should not expire
* and thus a separate password policy should apply to this group
@@ -67,27 +46,6 @@ public class IPAKerberosOperationHandler extends KerberosOperationHandler {
private String userPrincipalGroup = null;
/**
- * The format used for krbPasswordExpiry
- */
- private final SimpleDateFormat expiryFormat = new SimpleDateFormat("yyyyMMddHHmmss.SSS'Z'");
-
- /**
- * Time zone for krbPasswordExpiry
- */
- private static final TimeZone UTC = TimeZone.getTimeZone("UTC");
-
- /**
- * Years to add for password expiry
- */
- private static final int PASSWORD_EXPIRY_YEAR = 30;
-
- /**
- * A regular expression pattern to use to parse the key number from the text captured from the
- * kvno command
- */
- private final static Pattern PATTERN_GET_KEY_NUMBER = Pattern.compile("^.*?: kvno = (\\d+).*$", Pattern.DOTALL);
-
- /**
* A String containing the resolved path to the ipa executable
*/
private String executableIpaGetKeytab = null;
@@ -98,31 +56,6 @@ public class IPAKerberosOperationHandler extends KerberosOperationHandler {
private String executableIpa = null;
/**
- * A String containing the resolved path to the kinit executable
- */
- private String executableKinit = null;
-
- /**
- * A String containing the resolved path to the ipa-getkeytab executable
- */
- private String executableKvno = null;
-
- /**
- * A boolean indicating if password expiry should be set
- */
- private boolean usePasswordExpiry = false;
-
- /**
- * An int indicating the time out in seconds for the password chat;
- */
- private int timeout = DEFAULT_PASSWORD_CHAT_TIMEOUT;
-
- /**
- * Credentials context stores a handler to the ccache so it can be reused and removed on request
- */
- private CredentialsContext credentialsContext;
-
- /**
* Prepares and creates resources to be used by this KerberosOperationHandler
* <p/>
* It is expected that this KerberosOperationHandler will not be used before this call.
@@ -139,84 +72,27 @@ public class IPAKerberosOperationHandler extends KerberosOperationHandler {
* @throws KerberosOperationException if an unexpected error occurred
*/
@Override
- public void open(PrincipalKeyCredential administratorCredentials, String realm,
- Map<String, String> kerberosConfiguration)
- throws KerberosOperationException {
-
- setAdministratorCredential(administratorCredentials);
- setDefaultRealm(realm);
+ public void open(PrincipalKeyCredential administratorCredentials, String realm, Map<String, String> kerberosConfiguration)
+ throws KerberosOperationException {
if (kerberosConfiguration != null) {
- // todo: ignore if ipa managed krb5.conf?
- setKeyEncryptionTypes(translateEncryptionTypes(kerberosConfiguration.get(KERBEROS_ENV_ENCRYPTION_TYPES), "\\s+"));
- setExecutableSearchPaths(kerberosConfiguration.get(KERBEROS_ENV_EXECUTABLE_SEARCH_PATHS));
- setUserPrincipalGroup(kerberosConfiguration.get(KERBEROS_ENV_USER_PRINCIPAL_GROUP));
- setAdminServerHost(kerberosConfiguration.get(KERBEROS_ENV_ADMIN_SERVER_HOST));
- setUsePasswordExpiry(kerberosConfiguration.get(KERBEROS_ENV_SET_PASSWORD_EXPIRY));
- setTimeout(kerberosConfiguration.get(KERBEROS_ENV_PASSWORD_CHAT_TIMEOUT));
- } else {
- setKeyEncryptionTypes(null);
- setAdminServerHost(null);
- setExecutableSearchPaths((String) null);
- setUserPrincipalGroup(null);
- setUsePasswordExpiry(null);
- setTimeout(null);
+ userPrincipalGroup = kerberosConfiguration.get(KERBEROS_ENV_USER_PRINCIPAL_GROUP);
}
// Pre-determine the paths to relevant Kerberos executables
executableIpa = getExecutable("ipa");
- executableKvno = getExecutable("kvno");
- executableKinit = getExecutable("kinit");
executableIpaGetKeytab = getExecutable("ipa-getkeytab");
- credentialsContext = new CredentialsContext(administratorCredentials);
- cachedKeytabs = new HashMap<>();
- expiryFormat.setTimeZone(UTC);
-
- setOpen(true);
- }
-
- private void setUsePasswordExpiry(String usePasswordExpiry) {
- if (usePasswordExpiry == null) {
- this.usePasswordExpiry = false;
- return;
- }
-
- if (usePasswordExpiry.equalsIgnoreCase("true")) {
- this.usePasswordExpiry = true;
- } else {
- this.usePasswordExpiry = false;
- }
- }
-
- private void setTimeout(String timeout) {
- if (timeout == null || timeout.isEmpty()) {
- this.timeout = DEFAULT_PASSWORD_CHAT_TIMEOUT;
- return;
- }
-
- try {
- this.timeout = Integer.parseInt(timeout);
- } catch (NumberFormatException e) {
- this.timeout = DEFAULT_PASSWORD_CHAT_TIMEOUT;
- }
+ super.open(administratorCredentials, realm, kerberosConfiguration);
}
@Override
public void close() throws KerberosOperationException {
- if (isOpen()) {
- credentialsContext.delete();
- }
-
- // There is nothing to do here.
- setOpen(false);
-
+ userPrincipalGroup = null;
executableIpa = null;
- executableKvno = null;
executableIpaGetKeytab = null;
- executableKinit = null;
- credentialsContext = null;
- cachedKeytabs = null;
+
+ super.close();
}
/**
@@ -226,190 +102,121 @@ public class IPAKerberosOperationHandler extends KerberosOperationHandler {
* the result from STDOUT to determine if the presence of the specified principal.
*
* @param principal a String containing the principal to test
+ * @param service a boolean value indicating whether the principal is for a service or not
* @return true if the principal exists; false otherwise
* @throws KerberosOperationException if an unexpected error occurred
*/
@Override
- public boolean principalExists(String principal)
- throws KerberosOperationException {
-
- LOG.debug("Entering principal exists");
+ public boolean principalExists(String principal, boolean service)
+ throws KerberosOperationException {
if (!isOpen()) {
throw new KerberosOperationException("This operation handler has not been opened");
}
- if (principal == null) {
- return false;
- } else if (isServicePrincipal(principal)) {
- return true;
- } else {
- // TODO: fix exception check to only check for relevant exceptions
- try {
- DeconstructedPrincipal deconstructedPrincipal = createDeconstructPrincipal(principal);
- LOG.debug("Running IPA command user-show");
+ if (!StringUtils.isEmpty(principal)) {
+ DeconstructedPrincipal deconstructedPrincipal = createDeconstructPrincipal(principal);
+ String principalName = deconstructedPrincipal.getPrincipalName();
- // Create the ipa query to execute:
- ShellCommandUtil.Result result = invokeIpa(String.format("user-show %s", deconstructedPrincipal.getPrincipalName()));
- if (result.isSuccessful()) {
- return true;
- }
- } catch (KerberosOperationException e) {
- LOG.error("Cannot invoke IPA: " + e);
- throw e;
+ String[] ipaCommand = new String[]{
+ (service) ? "service-show" : "user-show",
+ principalName
+ };
+
+ ShellCommandUtil.Result result = invokeIpa(ipaCommand);
+ if (result.isSuccessful()) {
+ return true;
}
}
return false;
}
-
/**
- * Creates a new principal in a previously configured IPA Realm
- * <p/>
- * This implementation creates a query to send to the kadmin shell command and then interrogates
- * the result from STDOUT to determine if the operation executed successfully.
+ * Creates a new principal in a previously configured KDC.
+ * <p>
+ * This implementation uses the ipa shell to create either a user or service account. No password
+ * will be set for either account type. The password (or key) will be automatically generated by
+ * the IPA server when exporting the keytab entry. Upon success, this method will always return
+ * <code>0</code> as the key number since the value is not generated until the keytab entry is
+ * exported.
*
- * @param principal a String containing the principal add
- * @param password a String containing the password to use when creating the principal
+ * @param principal a String containing the principal to add
+ * @param password a String containing the password to use when creating the principal (ignored)
* @param service a boolean value indicating whether the principal is to be created as a service principal or not
- * @return an Integer declaring the generated key number
- * @throws KerberosKDCConnectionException if a connection to the KDC cannot be made
+ * @return an Integer declaring the generated key number (always 0)
+ * @throws KerberosOperationException
*/
@Override
public Integer createPrincipal(String principal, String password, boolean service)
- throws KerberosOperationException {
+ throws KerberosOperationException {
if (!isOpen()) {
throw new KerberosOperationException("This operation handler has not been opened");
}
- if ((principal == null) || principal.isEmpty()) {
+ if (StringUtils.isEmpty(principal)) {
throw new KerberosOperationException("Failed to create new principal - no principal specified");
- } else if (((password == null) || password.isEmpty()) && service) {
- throw new KerberosOperationException("Failed to create new user principal - no password specified");
- } else {
- DeconstructedPrincipal deconstructedPrincipal = createDeconstructPrincipal(principal);
-
- if (service) {
- // Create the ipa query: service-add --ok-as-delegate <principal>
- ShellCommandUtil.Result result = invokeIpa(String.format("service-add %s", principal));
- if (result.isSuccessful()) {
- // IPA does not generate encryption types when no keytab has been generated
- // So getKeyNumber(principal) cannot be used.
- // createKeytabCredentials(principal, password);
- // return getKeyNumber(principal);
- return 0;
- } else {
- LOG.error("Failed to execute ipa query: service-add --ok-as-delegate=TRUE {}\nSTDOUT: {}\nSTDERR: {}",
- principal, result.getStdout(), result.getStderr());
- throw new KerberosOperationException(String.format("Failed to create service principal for %s\nSTDOUT: %s\nSTDERR: %s",
- principal, result.getStdout(), result.getStderr()));
- }
- } else {
- if (!StringUtils.isAllLowerCase(deconstructedPrincipal.getPrincipalName())) {
- LOG.warn(deconstructedPrincipal.getPrincipalName() + " is not in lowercase. FreeIPA does not recognize user " +
- "principals that are not entirely in lowercase. This can lead to issues with kinit and keytabs. Make " +
- "sure users are in lowercase ");
- }
- // Create the ipa query: user-add <username> --principal=<principal_name> --first <primary> --last <primary>
- // set-attr userPassword="<password>"
- // first and last are required for IPA so we make it equal to the primary
- // the --principal arguments makes sure that Kerberos keys are available for use in getKeyNumber
- ShellCommandUtil.Result result = invokeIpa(String.format("user-add %s --principal=%s --first %s --last %s --setattr userPassword=%s",
- deconstructedPrincipal.getPrimary(), deconstructedPrincipal.getPrincipalName(),
- deconstructedPrincipal.getPrimary(), deconstructedPrincipal.getPrimary(), password));
-
- if (!result.isSuccessful()) {
- throw new KerberosOperationException(String.format("Failed to create user principal for %s\nSTDOUT: %s\nSTDERR: %s",
- principal, result.getStdout(), result.getStderr()));
- }
-
- if (getUserPrincipalGroup() != null && !getUserPrincipalGroup().isEmpty()) {
- result = invokeIpa(String.format("group-add-member %s --users=%s",
- getUserPrincipalGroup(), deconstructedPrincipal.getPrimary()));
- if (!result.isSuccessful()) {
- throw new KerberosOperationException(String.format("Failed to create user principal for %s\nSTDOUT: %s\nSTDERR: %s",
- principal, result.getStdout(), result.getStderr()));
- }
- }
-
- if (!usePasswordExpiry) {
- updatePassword(deconstructedPrincipal.getPrimary(), password);
- return getKeyNumber(principal);
- }
-
- Calendar calendar = Calendar.getInstance();
- calendar.add(Calendar.YEAR, PASSWORD_EXPIRY_YEAR);
+ }
- result = invokeIpa(String.format("user-mod %s --setattr krbPasswordExpiration=%s",
- deconstructedPrincipal.getPrimary(), expiryFormat.format(calendar.getTime())));
+ DeconstructedPrincipal deconstructedPrincipal = createDeconstructPrincipal(principal);
+ String normalizedPrincipal = deconstructedPrincipal.getNormalizedPrincipal();
- if (result.isSuccessful()) {
- return getKeyNumber(principal);
- }
+ String[] ipaCommand;
+ if (service) {
+ ipaCommand = new String[]{
+ "service-add",
+ normalizedPrincipal
+ };
+ } else {
+ String principalName = deconstructedPrincipal.getPrincipalName();
- throw new KerberosOperationException(String.format("Unknown error while creating principal for %s\n" +
- "STDOUT: %s\n" +
- "STDERR: %s\n",
- principal, result.getStdout(), result.getStderr()));
+ if (!principalName.equals(principal.toLowerCase())) {
+ LOG.warn("{} is not in lowercase. FreeIPA does not recognize user " +
+ "principals that are not entirely in lowercase. This can lead to issues with kinit and keytabs. Make " +
+ "sure users are in lowercase.", principalName);
}
- }
- }
- /**
- * Updates the password for an existing user principal in a previously configured IPA KDC
- * <p/>
- * This implementation creates a query to send to the ipa shell command and then interrogates
- * the exit code to determine if the operation executed successfully.
- *
- * @param principal a String containing the principal to update
- * @param password a String containing the password to set
- * @return an Integer declaring the new key number
- * @throws KerberosOperationException if an unexpected error occurred
- */
- @Override
- public Integer setPrincipalPassword(String principal, String password) throws KerberosOperationException {
- if (!isOpen()) {
- throw new KerberosOperationException("This operation handler has not been opened");
+ ipaCommand = new String[]{
+ "user-add",
+ deconstructedPrincipal.getPrimary(),
+ "--principal",
+ principalName,
+ "--first",
+ deconstructedPrincipal.getPrimary(),
+ "--last",
+ deconstructedPrincipal.getPrimary()
+ };
}
- if ((principal == null) || principal.isEmpty()) {
- throw new KerberosOperationException("Failed to set password - no principal specified");
- } else if ((password == null) || password.isEmpty()) {
- throw new KerberosOperationException("Failed to set password - no password specified");
- } else if (!isServicePrincipal(principal)) {
- DeconstructedPrincipal deconstructedPrincipal = createDeconstructPrincipal(principal);
-
- if (usePasswordExpiry) {
- Calendar calendar = Calendar.getInstance();
- calendar.add(Calendar.YEAR, PASSWORD_EXPIRY_YEAR);
+ ShellCommandUtil.Result result = invokeIpa(ipaCommand);
+ if (!result.isSuccessful()) {
+ String message = String.format("Failed to create principal for %s\n%s\nSTDOUT: %s\nSTDERR: %s",
+ normalizedPrincipal, StringUtils.join(ipaCommand, " "), result.getStdout(), result.getStderr());
+ LOG.error(message);
- // Create the ipa query: user-mod <user> --setattr userPassword=<password>
- invokeIpa(String.format("user-mod %s --setattr userPassword=%s", deconstructedPrincipal.getPrimary(), password));
+ String stdErr = result.getStderr();
- List<String> command = new ArrayList<>();
- command.add(executableIpa);
- command.add("user-mod");
- command.add(deconstructedPrincipal.getPrimary());
- command.add("--setattr");
- command.add(String.format("krbPasswordExpiration=%s", expiryFormat.format(calendar.getTime())));
- ShellCommandUtil.Result result = executeCommand(command.toArray(new String[command.size()]));
- if (!result.isSuccessful()) {
- throw new KerberosOperationException("Failed to set password expiry");
- }
+ if ((stdErr != null) &&
+ ((service && stdErr.contains(String.format("service with name \"%s\" already exists", normalizedPrincipal))) ||
+ (!service && stdErr.contains(String.format("user with name \"%s\" already exists", deconstructedPrincipal.getPrimary()))))) {
+ throw new KerberosPrincipalAlreadyExistsException(principal);
} else {
- updatePassword(deconstructedPrincipal.getPrimary(), password);
+ throw new KerberosOperationException(String.format("Failed to create principal for %s\nSTDOUT: %s\nSTDERR: %s",
+ normalizedPrincipal, result.getStdout(), result.getStderr()));
}
- } else {
- ShellCommandUtil.Result result = invokeIpa(String.format("service-show %s", principal));
- // ignore the keytab but set the password for this principal
- if (result.isSuccessful() && result.getStdout().contains("Keytab: False")) {
- LOG.debug("Found service principal {} without password/keytab. Setting one", principal);
- createKeytab(principal, password, 0);
+ }
+
+ if ((!service) && !StringUtils.isEmpty(userPrincipalGroup)) {
+ result = invokeIpa(new String[]{"group-add-member", userPrincipalGroup, "--users", deconstructedPrincipal.getPrimary()});
+ if (!result.isSuccessful()) {
+ LOG.warn("Failed to add account for {} to group {}: \nSTDOUT: {}\nSTDERR: {}",
+ normalizedPrincipal, userPrincipalGroup, result.getStdout(), result.getStderr());
}
}
- return getKeyNumber(principal);
+
+ // Always return 0 since we do not have a key to get a key number for.
+ return 0;
}
/**
@@ -418,6 +225,7 @@ public class IPAKerberosOperationHandler extends KerberosOperationHandler {
* The implementation is specific to a particular type of KDC.
*
* @param principal a String containing the principal to remove
+ * @param service a boolean value indicating whether the principal is for a service or not
* @return true if the principal was successfully removed; otherwise false
* @throws KerberosKDCConnectionException if a connection to the KDC cannot be made
* @throws KerberosAdminAuthenticationException if the administrator credentials fail to authenticate
@@ -425,696 +233,95 @@ public class IPAKerberosOperationHandler extends KerberosOperationHandler {
* @throws KerberosOperationException if an unexpected error occurred
*/
@Override
- public boolean removePrincipal(String principal) throws KerberosOperationException {
+ public boolean removePrincipal(String principal, boolean service) throws KerberosOperationException {
if (!isOpen()) {
throw new KerberosOperationException("This operation handler has not been opened");
}
- if ((principal == null) || principal.isEmpty()) {
- throw new KerberosOperationException("Failed to remove new principal - no principal specified");
- } else {
- ShellCommandUtil.Result result = null;
- if (isServicePrincipal(principal)) {
- result = invokeIpa(String.format("service-del %s", principal));
- } else {
- DeconstructedPrincipal deconstructedPrincipal = createDeconstructPrincipal(principal);
- result = invokeIpa(String.format("user-del %s", deconstructedPrincipal.getPrincipalName()));
- }
- return result.isSuccessful();
+ if (StringUtils.isEmpty(principal)) {
+ throw new KerberosOperationException("Failed to remove principal - no principal specified");
}
- }
- /**
- * Sets the name of the group where user principals should be members of
- *
- * @param userPrincipalGroup the name of the group
- */
- public void setUserPrincipalGroup(String userPrincipalGroup) {
- this.userPrincipalGroup = userPrincipalGroup;
- }
+ DeconstructedPrincipal deconstructedPrincipal = createDeconstructPrincipal(principal);
- /**
- * Gets the name of the group where user principals should be members of
- *
- * @return name of the group where user principals should be members of
- */
- public String getUserPrincipalGroup() {
- return this.userPrincipalGroup;
- }
+ String[] ipaCommand = (service)
+ ? new String[]{"service-del", deconstructedPrincipal.getNormalizedPrincipal()}
+ : new String[]{"user-del", deconstructedPrincipal.getPrincipalName()};
- /**
- * Sets the KDC administrator server host address
- *
- * @param adminServerHost the ip address or FQDN of the IPA administrator server
- */
- public void setAdminServerHost(String adminServerHost) {
- this.adminServerHost = adminServerHost;
+ return invokeIpa(ipaCommand).isSuccessful();
}
- /**
- * Gets the IP address or FQDN of the IPA administrator server
- *
- * @return the IP address or FQDN of the IPA administrator server
- */
- public String getAdminServerHost() {
- return this.adminServerHost;
+ @Override
+ protected String[] getKinitCommand(String executableKinit, PrincipalKeyCredential credentials, String credentialsCache) {
+ return new String[]{
+ executableKinit,
+ "-c",
+ credentialsCache,
+ credentials.getPrincipal()
+ };
}
- /**
- * Reads data from a stream without blocking and when available. Allows some time for the
- * stream to become ready.
- *
- * @param stdin the stdin BufferedReader to read from
- * @param stderr the stderr BufferedReader in case something goes wrong
- * @return a String with available data
- * @throws KerberosOperationException if a timeout happens
- * @throws IOException when somethings goes wrong with the underlying stream
- * @throws InterruptedException if the thread is interrupted
- */
- private String readData(BufferedReader stdin, BufferedReader stderr) throws KerberosOperationException, IOException, InterruptedException {
- char[] data = new char[1024];
- StringBuilder sb = new StringBuilder();
-
- int count = 0;
- while (!stdin.ready()) {
- Thread.sleep(1000L);
- if (count >= timeout) {
- char[] err_data = new char[1024];
- StringBuilder err = new StringBuilder();
- while (stderr.ready()) {
- stderr.read(err_data);
- err.append(err_data);
+ @Override
+ protected void exportKeytabFile(String principal, String keytabFileDestinationPath, Set<EncryptionType> keyEncryptionTypes) throws KerberosOperationException {
+ String encryptionTypeSpec = null;
+ if (!CollectionUtils.isEmpty(keyEncryptionTypes)) {
+ StringBuilder encryptionTypeSpecBuilder = new StringBuilder();
+ for (EncryptionType encryptionType : keyEncryptionTypes) {
+ if (encryptionTypeSpecBuilder.length() > 0) {
+ encryptionTypeSpecBuilder.append(',');
}
- throw new KerberosOperationException("No answer data available from stdin stream. STDERR: " + err);
+ encryptionTypeSpecBuilder.append(encryptionType.getName());
}
- count++;
- }
- while (stdin.ready()) {
- stdin.read(data);
- sb.append(data);
+ encryptionTypeSpec = encryptionTypeSpecBuilder.toString();
}
- return sb.toString();
- }
-
- /**
- * Updates a password for a (user) principal. This is done by first setting a random password and
- * then invoking kInit to directly set the password. This is done to circumvent issues with expired
- * password in IPA, as IPA needs passwords set by the admin to be set again by the user. Note that
- * this resets the current principal to the principal specified here. To invoke further administrative
- * commands a new kInit to admin is required.
- *
- * @param principal The principal user name that needs to be updated
- * @param password The new password
- * @throws KerberosOperationException if something is not as expected
- */
- private void updatePassword(String principal, String password) throws KerberosOperationException {
- BufferedReader reader = null;
- BufferedReader stderr = null;
- OutputStreamWriter out = null;
-
- LOG.debug("Updating password for: {}", principal);
-
- UUID uuid = UUID.randomUUID();
- String fileName = System.getProperty("java.io.tmpdir") +
- File.pathSeparator +
- "krb5cc_" + uuid;
-
- try {
- ShellCommandUtil.Result result = invokeIpa(String.format("user-mod %s --random", principal));
- if (!result.isSuccessful()) {
- throw new KerberosOperationException(result.getStderr());
- }
- Pattern pattern = Pattern.compile("password: (.*)");
- Matcher matcher = pattern.matcher(result.getStdout());
- if (!matcher.find()) {
- throw new KerberosOperationException("Unexpected response from ipa: " + result.getStdout());
- }
- String old_password = matcher.group(1);
-
- String credentialsCache = String.format("FILE:%s", fileName);
- Process process = Runtime.getRuntime().exec(new String[]{executableKinit, "-c", credentialsCache, principal});
- reader = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8));
- stderr = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8));
- out = new OutputStreamWriter(process.getOutputStream());
-
- String data = readData(reader, stderr);
- if (!data.startsWith("Password")) {
- process.destroy();
- throw new KerberosOperationException("Unexpected response from kinit while trying to password for "
- + principal + " got: " + data);
- }
- LOG.debug("Sending old password");
- out.write(old_password);
- out.write('\n');
- out.flush();
-
- data = readData(reader, stderr);
- if (!data.contains("Enter")) {
- process.destroy();
- throw new KerberosOperationException("Unexpected response from kinit while trying to password for "
- + principal + " got: " + data);
- }
- LOG.debug("Sending new password");
- out.write(password);
- out.write('\n');
- out.flush();
-
- data = readData(reader, stderr);
- if (!data.contains("again")) {
- process.destroy();
- throw new KerberosOperationException("Unexpected response from kinit while trying to password for "
- + principal + " got: " + data);
- }
- LOG.debug("Sending new password again");
- out.write(password);
- out.write('\n');
- out.flush();
+ String[] createKeytabFileCommand = (StringUtils.isEmpty(encryptionTypeSpec))
+ ? new String[]{executableIpaGetKeytab, "-s", getAdminServerHost(), "-p", principal, "-k", keytabFileDestinationPath}
+ : new String[]{executableIpaGetKeytab, "-s", getAdminServerHost(), "-e", encryptionTypeSpec, "-p", principal, "-k", keytabFileDestinationPath};
- process.waitFor();
- } catch (IOException e) {
- LOG.error("Cannot read stream: " + e);
- throw new KerberosOperationException(e.getMessage());
- } catch (InterruptedException e) {
- LOG.error("Process interrupted: " + e);
- throw new KerberosOperationException(e.getMessage());
- } finally {
- try {
- if (out != null)
- out.close();
- } catch (IOException e) {
- LOG.warn("Cannot close out stream: " + e);
- }
- try {
- if (reader != null)
- reader.close();
- } catch (IOException e) {
- LOG.warn("Cannot close stdin stream: " + e);
- }
- try {
- if (stderr != null)
- stderr.close();
- } catch (IOException e) {
- LOG.warn("Cannot close stderr stream: " + e);
- }
- File ccache = new File(fileName);
- ccache.delete();
+ ShellCommandUtil.Result result = executeCommand(createKeytabFileCommand);
+ if (!result.isSuccessful()) {
+ String message = String.format("Failed to export the keytab file for %s:\n\tExitCode: %s\n\tSTDOUT: %s\n\tSTDERR: %s",
+ principal, result.getExitCode(), result.getStdout(), result.getStderr());
+ LOG.warn(message);
+ throw new KerberosOperationException(message);
}
-
}
/**
* Invokes the ipa shell command with administrative credentials to issue queries
*
- * @param query a String containing the query to send to the kdamin command
+ * @param query a String containing the query to send to the ipa command
* @return a ShellCommandUtil.Result containing the result of the operation
* @throws KerberosOperationException if an unexpected error occurred
*/
- protected ShellCommandUtil.Result invokeIpa(String query)
- throws KerberosOperationException {
- LOG.debug("Entering invokeipa");
+ private ShellCommandUtil.Result invokeIpa(String[] query) throws KerberosOperationException {
- ShellCommandUtil.Result result = null;
-
- if ((query == null) || query.isEmpty()) {
+ if ((query == null) || (query.length == 0)) {
throw new KerberosOperationException("Missing ipa query");
}
- PrincipalKeyCredential administratorCredentials = getAdministratorCredential();
- String defaultRealm = getDefaultRealm();
-
- List<String> command = new ArrayList<>();
- List<String> kinit = new ArrayList<>();
- String adminPrincipal = (administratorCredentials == null)
- ? null
- : administratorCredentials.getPrincipal();
-
- if ((adminPrincipal == null) || adminPrincipal.isEmpty()) {
- throw new KerberosOperationException("No admin principal for ipa available - " +
- "this KerberosOperationHandler may not have been opened.");
- }
-
- if ((executableIpa == null) || executableIpa.isEmpty()) {
- throw new KerberosOperationException("No path for ipa is available - " +
- "this KerberosOperationHandler may not have been opened.");
+ if (StringUtils.isEmpty(executableIpa)) {
+ throw new KerberosOperationException("No path for ipa is available - this KerberosOperationHandler may not have been opened.");
}
- // Set the ipa interface to be ipa
- command.add(executableIpa);
- command.add(query);
-
- if (LOG.isDebugEnabled()) {
- LOG.debug("Executing: {}", createCleanCommand(command));
- }
+ String[] command = new String[query.length + 1];
+ command[0] = executableIpa;
+ System.arraycopy(query, 0, command, 1, query.length);
- List<String> fixedCommand = fixCommandList(command);
- result = executeCommand(fixedCommand.toArray(new String[fixedCommand.size()]));
-
-
- LOG.debug("Done invokeipa");
- return result;
- }
+ ShellCommandUtil.Result result = executeCommand(command);
- /**
- * Executes a shell command in a credentials context
- * <p/>
- * See {@link org.apache.ambari.server.utils.ShellCommandUtil#runCommand(String[])}
- *
- * @param command an array of String value representing the command and its arguments
- * @return a ShellCommandUtil.Result declaring the result of the operation
- * @throws KerberosOperationException
- */
- @Override
- protected ShellCommandUtil.Result executeCommand(String[] command)
- throws KerberosOperationException {
- return credentialsContext.executeCommand(command);
- }
-
- /**
- * Rebuilds the command line to make sure space are converted to arguments
- *
- * @param command a List of items making up the command
- * @return the fixed command
- */
- private List<String> fixCommandList(List<String> command) {
- List<String> fixedCommandList = new ArrayList<>();
- Iterator<String> iterator = command.iterator();
-
- if (iterator.hasNext()) {
- fixedCommandList.add(iterator.next());
- }
-
- while (iterator.hasNext()) {
- String part = iterator.next();
-
- // split arguments
- if (part.contains(" ")) {
- StringTokenizer st = new StringTokenizer(part, " ");
- while (st.hasMoreElements()) {
- fixedCommandList.add(st.nextToken());
- }
- } else {
- fixedCommandList.add(part);
- }
- }
-
- return fixedCommandList;
- }
-
- /**
- * Build the ipa command string, replacing administrator password with "********"
- *
- * @param command a List of items making up the command
- * @return the cleaned command string
- */
- private String createCleanCommand(List<String> command) {
- StringBuilder cleanedCommand = new StringBuilder();
- Iterator<String> iterator = command.iterator();
-
- if (iterator.hasNext()) {
- cleanedCommand.append(iterator.next());
- }
-
- while (iterator.hasNext()) {
- String part = iterator.next();
-
- cleanedCommand.append(' ');
- cleanedCommand.append(part);
-
- if ("--setattr".equals(part)) {
- // Skip the password and use "********" instead
- String arg= null;
- if (iterator.hasNext()) {
- arg = iterator.next();
- if (arg.contains("userPassword")) {
- cleanedCommand.append("userPassword=******");
- } else {
- cleanedCommand.append(arg);
- }
- }
- }
- }
-
- return cleanedCommand.toString();
- }
-
- /**
- * Determine is a principal is a service principal
- *
- * @param principal
- * @return true if the principal is a (existing) service principal
- * @throws KerberosOperationException
- */
- private boolean isServicePrincipal(String principal)
- throws KerberosOperationException {
-
- if ((principal == null) || principal.isEmpty()) {
- throw new KerberosOperationException("Failed to determine principal type- no principal specified");
- } else if (!principal.contains("/")) {
- return false;
- }
-
- try {
- ShellCommandUtil.Result result = invokeIpa(String.format("service-show %s", principal));
-
- // TODO: unfortunately we can be in limbo if the "Keytab: False" is present
- if (result.isSuccessful()) {
- return true;
+ if (result.isSuccessful()) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Executed the following command:\n{}\nSTDOUT: {}\nSTDERR: {}",
+ StringUtils.join(command, " "), result.getStdout(), result.getStderr());
}
- } catch (KerberosOperationException e) {
- LOG.warn("Exception while invoking ipa service-show: " + e);
- return false;
- }
-
- return false;
- }
-
- /**
- * Retrieves the current key number assigned to the identity identified by the specified principal
- *
- * @param principal a String declaring the principal to look up
- * @return an Integer declaring the current key number
- * @throws KerberosKDCConnectionException if a connection to the KDC cannot be made
- * @throws KerberosAdminAuthenticationException if the administrator credentials fail to authenticate
- * @throws KerberosRealmException if the realm does not map to a KDC
- * @throws KerberosOperationException if an unexpected error occurred
- */
- private Integer getKeyNumber(String principal) throws KerberosOperationException {
- if (!isOpen()) {
- throw new KerberosOperationException("This operation handler has not been opened");
- }
-
- if ((principal == null) || principal.isEmpty()) {
- throw new KerberosOperationException("Failed to get key number for principal - no principal specified");
} else {
- // Create the kvno query: <principal>
- List<String> command = new ArrayList<>();
- command.add(executableKvno);
- command.add(principal);
-
- ShellCommandUtil.Result result = executeCommand(command.toArray(new String[command.size()]));
- String stdOut = result.getStdout();
- if (stdOut == null) {
- String message = String.format("Failed to get key number for %s:\n\tExitCode: %s\n\tSTDOUT: NULL\n\tSTDERR: %s",
- principal, result.getExitCode(), result.getStderr());
- LOG.warn(message);
- throw new KerberosOperationException(message);
- }
-
- Matcher matcher = PATTERN_GET_KEY_NUMBER.matcher(stdOut);
- if (matcher.matches()) {
- NumberFormat numberFormat = NumberFormat.getIntegerInstance();
- String keyNumber = matcher.group(1);
-
- numberFormat.setGroupingUsed(false);
- try {
- Number number = numberFormat.parse(keyNumber);
- return (number == null) ? 0 : number.intValue();
- } catch (ParseException e) {
- String message = String.format("Failed to get key number for %s - invalid key number value (%s):\n\tExitCode: %s\n\tSTDOUT: NULL\n\tSTDERR: %s",
- principal, keyNumber, result.getExitCode(), result.getStderr());
- LOG.warn(message);
- throw new KerberosOperationException(message);
- }
- } else {
- String message = String.format("Failed to get key number for %s - unexpected STDOUT data:\n\tExitCode: %s\n\tSTDOUT: NULL\n\tSTDERR: %s",
- principal, result.getExitCode(), result.getStderr());
- LOG.warn(message);
- throw new KerberosOperationException(message);
- }
-
- }
- }
-
- /*
- * Creates a key tab by using the ipa commandline utilities.
- *
- * @param principal a String containing the principal to test
- * @param password a String containing the password to use when creating the principal
- * @return
- * @throws KerberosOperationException
- */
- /*private Keytab createKeytabCredentials(String principal, String password)
- throws KerberosOperationException {
-
- if ((principal == null) || principal.isEmpty()) {
- throw new KerberosOperationException("Failed to create keytab file, missing principal");
- }
-
- BufferedReader reader = null;
- BufferedReader stderr = null;
- OutputStreamWriter out = null;
-
- UUID uuid = UUID.randomUUID();
- String fileName = System.getProperty("java.io.tmpdir") +
- File.pathSeparator +
- "ambari." + uuid.toString();
-
- try {
- // TODO: add ciphers
- Process p = credentialsContext.exec(new String[]{executableIpaGetKeytab, "-s",
- getAdminServerHost(), "-p", principal, "-k", fileName, "-P"});
- reader = new BufferedReader(new InputStreamReader(p.getInputStream(), StandardCharsets.UTF_8));
- stderr = new BufferedReader(new InputStreamReader(p.getErrorStream(), StandardCharsets.UTF_8));
- out = new OutputStreamWriter(p.getOutputStream());
-
- String data = readData(reader, stderr);
- if (!data.startsWith("New")) {
- p.destroy();
- throw new KerberosOperationException("Unexpected response from ipa-getkeytab while trying to password for "
- + principal + " got: " + data);
- }
- LOG.debug("Sending password");
- out.write(password);
- out.write('\n');
- out.flush();
-
- data = readData(reader, stderr);
- if (!data.contains("Verify")) {
- p.destroy();
- throw new KerberosOperationException("Unexpected response from ipa-getkeytab while trying to password for "
- + principal + " got: " + data);
- }
- LOG.debug("Sending new password");
- out.write(password);
- out.write('\n');
- out.flush();
-
- p.waitFor();
- } catch (IOException e) {
- LOG.error("Cannot read stream: " + e);
- throw new KerberosOperationException(e.getMessage());
- } catch (InterruptedException e) {
- LOG.error("Process interrupted: " + e);
- throw new KerberosOperationException(e.getMessage());
- } finally {
- try {
- if (out != null)
- out.close();
- } catch (IOException e) {
- LOG.warn("Cannot close out stream: " + e);
- }
- try {
- if (reader != null)
- reader.close();
- } catch (IOException e) {
- LOG.warn("Cannot close stdin stream: " + e);
- }
- try {
- if (stderr != null)
- stderr.close();
- } catch (IOException e) {
- LOG.warn("Cannot close stderr stream: " + e);
- }
- }
-
- File keytabFile = new File(fileName);
- Keytab keytab = readKeytabFile(keytabFile);
- keytabFile.delete();
-
- return keytab;
- }*/
-
- /**
- * Creates a key tab by using the ipa commandline utilities. It ignores key number and password
- * as this will be handled by IPA
- *
- * @param principal a String containing the principal to test
- * @param password (IGNORED) a String containing the password to use when creating the principal
- * @param keyNumber (IGNORED) a Integer indicating the key number for the keytab entries
- * @return
- * @throws KerberosOperationException
- */
- @Override
- protected Keytab createKeytab(String principal, String password, Integer keyNumber)
- throws KerberosOperationException {
-
- if ((principal == null) || principal.isEmpty()) {
- throw new KerberosOperationException("Failed to create keytab file, missing principal");
- }
-
- // use cache if available
- if (cachedKeytabs.containsKey(principal)) {
- return cachedKeytabs.get(principal);
- }
-
- UUID uuid = UUID.randomUUID();
- String fileName = System.getProperty("java.io.tmpdir") +
- File.pathSeparator +
- "ambari." + uuid;
-
- // TODO: add ciphers
- List<String> command = new ArrayList<>();
- command.add(executableIpaGetKeytab);
- command.add("-s");
- command.add(getAdminServerHost());
- command.add("-p");
- command.add(principal);
- command.add("-k");
- command.add(fileName);
-
- // TODO: is it really required to set the password?
- ShellCommandUtil.Result result = executeCommand(command.toArray(new String[command.size()]));
- if (!result.isSuccessful()) {
- String message = String.format("Failed to get key number for %s:\n\tExitCode: %s\n\tSTDOUT: %s\n\tSTDERR: %s",
- principal, result.getExitCode(), result.getStdout(), result.getStderr());
- LOG.warn(message);
- throw new KerberosOperationException(message);
- }
-
- File keytabFile = new File(fileName);
- Keytab keytab = readKeytabFile(keytabFile);
- keytabFile.delete();
-
- cachedKeytabs.put(principal, keytab);
- return keytab;
- }
-
-
- /**
- * Credentials context executes commands wrapped with kerberos credentials
- */
- class CredentialsContext {
- private PrincipalKeyCredential credentials;
- Map<String, String> env = new HashMap<>();
- private String fileName;
- private List<Process> processes = new ArrayList<>();
-
- public CredentialsContext(PrincipalKeyCredential credentials) throws KerberosOperationException {
- this.credentials = credentials;
-
- UUID uuid = UUID.randomUUID();
- fileName = System.getProperty("java.io.tmpdir") +
- File.pathSeparator +
- "krb5cc_" + uuid;
- env.put("KRB5CCNAME", String.format("FILE:%s", fileName));
-
- init(credentials, fileName);
- }
-
- protected ShellCommandUtil.Result executeCommand(String[] command)
- throws KerberosOperationException {
-
- if ((command == null) || (command.length == 0)) {
- return null;
- } else {
- try {
- return ShellCommandUtil.runCommand(command, env);
- } catch (IOException e) {
- String message = String.format("Failed to execute the command: %s", e.getLocalizedMessage());
- LOG.error(message, e);
- throw new KerberosOperationException(message, e);
- } catch (InterruptedException e) {
- String message = String.format("Failed to wait for the command to complete: %s", e.getLocalizedMessage());
- LOG.error(message, e);
- throw new KerberosOperationException(message, e);
- }
- }
- }
-
- /**
- * Does a kinit to obtain a ticket for the specified principal and stores it in the specified cache
- *
- * @param credentials Credentials to be used to obtain the ticket
- * @param fileName Filename where to store the credentials
- * @throws KerberosOperationException In case the ticket cannot be obtained
- */
- private void init(PrincipalKeyCredential credentials, String fileName) throws KerberosOperationException {
- Process process;
- BufferedReader reader = null;
- OutputStreamWriter osw = null;
-
- LOG.debug("Entering doKinit");
- try {
- String credentialsCache = String.format("FILE:%s", fileName);
-
- LOG.debug("start subprocess {} {}", executableKinit, credentials.getPrincipal());
- process = Runtime.getRuntime().exec(new String[]{executableKinit, "-c", credentialsCache, credentials.getPrincipal()});
- reader = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8));
- osw = new OutputStreamWriter(process.getOutputStream());
-
- char[] data = new char[1024];
- StringBuilder sb = new StringBuilder();
-
- int count = 0;
- while (!reader.ready()) {
- Thread.sleep(1000L);
- if (count >= 5) {
- process.destroy();
- throw new KerberosOperationException("No answer from kinit");
- }
- count++;
- }
-
- while (reader.ready()) {
- reader.read(data);
- sb.append(data);
- }
-
- String line = sb.toString();
- LOG.debug("Reading a line: {}", line);
- if (!line.startsWith("Password")) {
- throw new KerberosOperationException("Unexpected response from kinit while trying to get ticket for "
- + credentials.getPrincipal() + " got: " + line);
- }
- osw.write(credentials.getKey());
- osw.write('\n');
- osw.close();
-
- process.waitFor();
-
- LOG.debug("done subprocess");
- } catch (IOException | InterruptedException e) {
- String message = String.format("Failed to execute the command: %s", e.getLocalizedMessage());
- LOG.error(message, e);
- throw new KerberosOperationException(message, e);
- } finally {
- Closeables.closeSilently(osw);
- Closeables.closeSilently(reader);
- }
-
- if (process.exitValue() != 0) {
- throw new KerberosOperationException("kinit failed for " + credentials.getPrincipal() + ". Wrong password?");
- }
-
- }
-
- public Process exec(String[] args) throws IOException {
- Process process = Runtime.getRuntime().exec(args);
- processes.add(process);
-
- return process;
- }
-
- public void delete() {
- File ccache = new File(fileName);
- ccache.delete();
- for (Process p : processes) {
- p.destroy();
- }
+ LOG.error("Failed to execute the following command:\n{}\nSTDOUT: {}\nSTDERR: {}",
+ StringUtils.join(command, " "), result.getStdout(), result.getStderr());
}
+ return result;
}
-
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KDCKerberosOperationHandler.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KDCKerberosOperationHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KDCKerberosOperationHandler.java
new file mode 100644
index 0000000..bf3ac22
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KDCKerberosOperationHandler.java
@@ -0,0 +1,391 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.serveraction.kerberos;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.security.credential.PrincipalKeyCredential;
+import org.apache.ambari.server.utils.ShellCommandUtil;
+import org.apache.commons.collections.MapUtils;
+import org.apache.directory.server.kerberos.shared.keytab.Keytab;
+import org.apache.directory.shared.kerberos.codec.types.EncryptionType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * KDCKerberosOperationHandler is an implementation of a KerberosOperationHandler providing
+ * functionality KDC-based Kerberos providers.
+ * <p>
+ * This implementation provides kinit functionality and keytab file caching utilities for classes.
+ */
+abstract class KDCKerberosOperationHandler extends KerberosOperationHandler {
+ private static final Logger LOG = LoggerFactory.getLogger(KDCKerberosOperationHandler.class);
+
+ /**
+ * The FQDN of the host where KDC administration server is
+ */
+ private String adminServerHost = null;
+
+ /**
+ * A map of principal names to {@link Keytab} entries to ensure a Keyab file is not created/exported
+ * for the same principal more than once.
+ */
+ private HashMap<String, Keytab> cachedKeytabs = null;
+
+ /**
+ * A String containing the resolved path to the kinit executable
+ */
+ private String executableKinit = null;
+
+ /**
+ * The absolute path to the KDC administrator's Kerberos ticket cache.
+ * <p>
+ * This path is created as as temporary file with a randomized name when this {@link KerberosOperationHandler}
+ * is open. It is destoryed when this {@link KerberosOperationHandler} is closed.
+ */
+ private File credentialsCacheFile = null;
+
+ /**
+ * A Map of environmet values to send to system command invocations.
+ * <p>
+ * This map is to be appened to any map of environment values passed in when
+ * invoking {@link KerberosOperationHandler#executeCommand(String[], Map, ShellCommandUtil.InteractiveHandler)}
+ */
+ private Map<String, String> environmentMap = null;
+
+ @Override
+ public void open(PrincipalKeyCredential administratorCredentials, String realm, Map<String, String> kerberosConfiguration)
+ throws KerberosOperationException {
+
+ super.open(administratorCredentials, realm, kerberosConfiguration);
+
+ if (kerberosConfiguration != null) {
+ adminServerHost = kerberosConfiguration.get(KERBEROS_ENV_ADMIN_SERVER_HOST);
+ }
+
+ // Pre-determine the paths to relevant Kerberos executables
+ executableKinit = getExecutable("kinit");
+
+ setOpen(init());
+ }
+
+ @Override
+ public void close() throws KerberosOperationException {
+
+ if (credentialsCacheFile != null) {
+ if (credentialsCacheFile.delete()) {
+ LOG.debug("Failed to remove the cache file, {}", credentialsCacheFile.getAbsolutePath());
+ }
+ credentialsCacheFile = null;
+ }
+
+ environmentMap = null;
+ executableKinit = null;
+ cachedKeytabs = null;
+ adminServerHost = null;
+
+ super.close();
+ }
+
+ /**
+ * Updates the password for an existing user principal in a previously configured IPA KDC
+ * <p/>
+ * This implementation creates a query to send to the ipa shell command and then interrogates
+ * the exit code to determine if the operation executed successfully.
+ *
+ * @param principal a String containing the principal to update
+ * @param password a String containing the password to set
+ * @param service a boolean value indicating whether the principal is for a service or not
+ * @return an Integer declaring the new key number
+ * @throws KerberosOperationException if an unexpected error occurred
+ */
+ @Override
+ public Integer setPrincipalPassword(String principal, String password, boolean service) throws KerberosOperationException {
+ if (!isOpen()) {
+ throw new KerberosOperationException("This operation handler has not been opened");
+ }
+
+ // It is expected that KerberosPrincipalDoesNotExistException is thrown if the principal does not exist.
+ // The caller expects so that it can attempt to set the password for a principal without checking
+ // to see if it exists first. If the principal does not exist and is required, the caller will
+ // create it. This saves a potentially unnecessary round trip to the KDC and back.
+ if(!principalExists(principal, service)) {
+ throw new KerberosPrincipalDoesNotExistException(String.format("Principal does not exist while attempting to set its password: %s", principal));
+ }
+
+ // This operation does nothing since a new key will be created when exporting the keytab file...
+ return 0;
+ }
+
+ /**
+ * Creates a key tab by using the ipa commandline utilities. It ignores key number and password
+ * as this will be handled by IPA
+ *
+ * @param principal a String containing the principal to test
+ * @param password (IGNORED) a String containing the password to use when creating the principal
+ * @param keyNumber (IGNORED) a Integer indicating the key number for the keytab entries
+ * @return the created Keytab
+ * @throws KerberosOperationException
+ */
+ @Override
+ protected Keytab createKeytab(String principal, String password, Integer keyNumber)
+ throws KerberosOperationException {
+
+ if ((principal == null) || principal.isEmpty()) {
+ throw new KerberosOperationException("Failed to create keytab file, missing principal");
+ }
+
+ // use cache if available
+ if (cachedKeytabs.containsKey(principal)) {
+ return cachedKeytabs.get(principal);
+ }
+
+ File keytabFile = null;
+
+ try {
+ try {
+ keytabFile = File.createTempFile("ambari_tmp", ".keytab");
+
+ // Remove the file else the command will fail...
+ if (!keytabFile.delete()) {
+ LOG.warn("Failed to remove temporary file to hold keytab. Exporting the keytab file for {} may fail.", principal);
+ }
+ } catch (IOException e) {
+ throw new KerberosOperationException(String.format("Failed to create the temporary file needed to hold the exported keytab file for %s: %s", principal, e.getLocalizedMessage()), e);
+ }
+
+
+ exportKeytabFile(principal, keytabFile.getAbsolutePath(), getKeyEncryptionTypes());
+
+ Keytab keytab = readKeytabFile(keytabFile);
+ cachedKeytabs.put(principal, keytab);
+ return keytab;
+ } finally {
+ if ((keytabFile != null) && keytabFile.exists()) {
+ if (!keytabFile.delete()) {
+ LOG.debug("Failed to remove the temporary keytab file, {}", keytabFile.getAbsolutePath());
+ }
+ }
+ }
+ }
+
+ /**
+ * Executes a shell command in a credentials context
+ * <p/>
+ * See {@link ShellCommandUtil#runCommand(String[])}
+ * <p>
+ * This implementation sets the proper environment for the custom <code>KRB5CCNAME </code> value.
+ *
+ * @param command an array of String value representing the command and its arguments
+ * @param envp a map of string, string of environment variables
+ * @param interactiveHandler a handler to provide responses to queries from the command,
+ * or null if no queries are expected
+ * @return a ShellCommandUtil.Result declaring the result of the operation
+ * @throws KerberosOperationException
+ */
+ @Override
+ protected ShellCommandUtil.Result executeCommand(String[] command, Map<String, String> envp, ShellCommandUtil.InteractiveHandler interactiveHandler)
+ throws KerberosOperationException {
+
+ Map<String, String> _envp;
+
+ if (MapUtils.isEmpty(environmentMap)) {
+ _envp = envp;
+ } else if (MapUtils.isEmpty(envp)) {
+ _envp = environmentMap;
+ } else {
+ _envp = new HashMap<>();
+ _envp.putAll(envp);
+ _envp.putAll(environmentMap);
+ }
+
+ return super.executeCommand(command, _envp, interactiveHandler);
+ }
+
+ String getAdminServerHost() {
+ return adminServerHost;
+ }
+
+ String getCredentialCacheFilePath() {
+ return (credentialsCacheFile == null) ? null : credentialsCacheFile.getAbsolutePath();
+ }
+
+ /**
+ * Return an array of Strings containing the command and the relavant arguments needed authenticate
+ * with the KDC and create the Kerberos ticket/credential cache.
+ *
+ * @param executableKinit the absolute path to the kinit executable
+ * @param credentials the KDC adminisrator's credentials
+ * @param credentialsCache the absolute path to the expected location of the Kerberos ticket/credential cache file
+ * @return an array of Strings containing the command to execute
+ */
+ protected abstract String[] getKinitCommand(String executableKinit, PrincipalKeyCredential credentials, String credentialsCache);
+
+ /**
+ * Export the requested keytab entries for a given principal into the specified file.
+ *
+ * @param principal the principal name
+ * @param keytabFileDestinationPath the absolute path to the keytab file
+ * @param keyEncryptionTypes a collection of encrption algorithm types indicating which ketyab entries are requested
+ * @throws KerberosOperationException
+ */
+ protected abstract void exportKeytabFile(String principal, String keytabFileDestinationPath, Set<EncryptionType> keyEncryptionTypes) throws KerberosOperationException;
+
+ /**
+ * Initialize the Kerberos ticket cache using the supplied KDC administrator's credentials.
+ * <p>
+ * A randomly named temporary file is created to store the Kerberos ticket cache for this {@link KerberosOperationHandler}'s
+ * session. The file will be removed upon closing when the session is complete. The geneated ticket cache
+ * filename is set in the environment variable map using the variable name "KRB5CCNAME". This will be passed
+ * in for all relevant-system commands.
+ *
+ * @return
+ * @throws KerberosOperationException
+ */
+ protected boolean init() throws KerberosOperationException {
+ if (credentialsCacheFile != null) {
+ if (!credentialsCacheFile.delete()) {
+ LOG.debug("Failed to remove the orphaned cache file, {}", credentialsCacheFile.getAbsolutePath());
+ }
+ credentialsCacheFile = null;
+ }
+
+ try {
+ credentialsCacheFile = File.createTempFile("ambari_krb_", "cc");
+ credentialsCacheFile.deleteOnExit();
+ ensureAmbariOnlyAccess(credentialsCacheFile);
+ } catch (IOException e) {
+ throw new KerberosOperationException(String.format("Failed to create the temporary file needed to hold the administrator ticket cache: %s", e.getLocalizedMessage()), e);
+ }
+
+ String credentialsCache = String.format("FILE:%s", credentialsCacheFile.getAbsolutePath());
+
+ environmentMap = new HashMap<>();
+ environmentMap.put("KRB5CCNAME", credentialsCache);
+
+ PrincipalKeyCredential credentials = getAdministratorCredential();
+
+ ShellCommandUtil.Result result = executeCommand(getKinitCommand(executableKinit, credentials, credentialsCache),
+ environmentMap,
+ new InteractivePasswordHandler(String.valueOf(credentials.getKey()), null));
+
+ if (!result.isSuccessful()) {
+ String message = String.format("Failed to kinit as the KDC administrator user, %s:\n\tExitCode: %s\n\tSTDOUT: %s\n\tSTDERR: %s",
+ credentials.getPrincipal(), result.getExitCode(), result.getStdout(), result.getStderr());
+ LOG.warn(message);
+ throw new KerberosAdminAuthenticationException(message);
+ }
+
+ cachedKeytabs = new HashMap<>();
+
+ return true;
+ }
+
+ /**
+ * Ensures that the owner of the Ambari server process is the only local user account able to
+ * read and write to the specified file or read, write to, and execute the specified directory.
+ *
+ * @param file the file or directory for which to modify access
+ */
+ private void ensureAmbariOnlyAccess(File file) throws AmbariException {
+ if (file.exists()) {
+ if (!file.setReadable(false, false) || !file.setReadable(true, true)) {
+ String message = String.format("Failed to set %s readable only by Ambari", file.getAbsolutePath());
+ LOG.warn(message);
+ throw new AmbariException(message);
+ }
+
+ if (!file.setWritable(false, false) || !file.setWritable(true, true)) {
+ String message = String.format("Failed to set %s writable only by Ambari", file.getAbsolutePath());
+ LOG.warn(message);
+ throw new AmbariException(message);
+ }
+
+ if (file.isDirectory()) {
+ if (!file.setExecutable(false, false) || !file.setExecutable(true, true)) {
+ String message = String.format("Failed to set %s executable by Ambari", file.getAbsolutePath());
+ LOG.warn(message);
+ throw new AmbariException(message);
+ }
+ } else {
+ if (!file.setExecutable(false, false)) {
+ String message = String.format("Failed to set %s not executable", file.getAbsolutePath());
+ LOG.warn(message);
+ throw new AmbariException(message);
+ }
+ }
+ }
+ }
+
+ /**
+ * InteractivePasswordHandler is a {@link ShellCommandUtil.InteractiveHandler}
+ * implementation that answers queries from kadmin or kdamin.local command for the admin and/or user
+ * passwords.
+ */
+ protected static class InteractivePasswordHandler implements ShellCommandUtil.InteractiveHandler {
+ /**
+ * The queue of responses to return
+ */
+ private LinkedList<String> responses;
+ private Queue<String> currentResponses;
+
+ /**
+ * Constructor.
+ *
+ * @param adminPassword the KDC administrator's password (optional)
+ * @param userPassword the user's password (optional)
+ */
+ InteractivePasswordHandler(String adminPassword, String userPassword) {
+ responses = new LinkedList<>();
+
+ if (adminPassword != null) {
+ responses.offer(adminPassword);
+ }
+
+ if (userPassword != null) {
+ responses.offer(userPassword);
+ responses.offer(userPassword); // Add a 2nd time for the password "confirmation" request
+ }
+
+ currentResponses = new LinkedList<>(responses);
+ }
+
+ @Override
+ public boolean done() {
+ return currentResponses.size() == 0;
+ }
+
+ @Override
+ public String getResponse(String query) {
+ return currentResponses.poll();
+ }
+
+ @Override
+ public void start() {
+ currentResponses = new LinkedList<>(responses);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosIdentityDataFile.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosIdentityDataFile.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosIdentityDataFile.java
index ddf3d1b..ae1217c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosIdentityDataFile.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosIdentityDataFile.java
@@ -36,6 +36,4 @@ public interface KerberosIdentityDataFile extends KerberosDataFile {
String KEYTAB_FILE_GROUP_NAME = "keytab_file_group_name";
String KEYTAB_FILE_GROUP_ACCESS = "keytab_file_group_access";
String KEYTAB_FILE_IS_CACHABLE = "keytab_file_is_cachable";
- String ONLY_KEYTAB_WRITE = "only_keytab_write";
-
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosIdentityDataFileWriter.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosIdentityDataFileWriter.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosIdentityDataFileWriter.java
index ea742bd..f55c6f4 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosIdentityDataFileWriter.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosIdentityDataFileWriter.java
@@ -68,8 +68,7 @@ public class KerberosIdentityDataFileWriter extends AbstractKerberosDataFileWrit
String principal, String principalType,
String keytabFilePath, String keytabFileOwnerName,
String keytabFileOwnerAccess, String keytabFileGroupName,
- String keytabFileGroupAccess, String keytabFileCanCache,
- String onlyKeytabWrite)
+ String keytabFileGroupAccess, String keytabFileCanCache)
throws IOException {
super.appendRecord(hostName,
serviceName,
@@ -81,8 +80,7 @@ public class KerberosIdentityDataFileWriter extends AbstractKerberosDataFileWrit
keytabFileOwnerAccess,
keytabFileGroupName,
keytabFileGroupAccess,
- keytabFileCanCache,
- onlyKeytabWrite);
+ keytabFileCanCache);
}
@Override
@@ -97,7 +95,6 @@ public class KerberosIdentityDataFileWriter extends AbstractKerberosDataFileWrit
KEYTAB_FILE_OWNER_ACCESS,
KEYTAB_FILE_GROUP_NAME,
KEYTAB_FILE_GROUP_ACCESS,
- KEYTAB_FILE_IS_CACHABLE,
- ONLY_KEYTAB_WRITE);
+ KEYTAB_FILE_IS_CACHABLE);
}
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosOperationHandler.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosOperationHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosOperationHandler.java
index 8749f81..948fd60 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosOperationHandler.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosOperationHandler.java
@@ -67,22 +67,7 @@ public abstract class KerberosOperationHandler {
/**
* Kerberos-env configuration property name: group
*/
- public final static String KERBEROS_ENV_USER_PRINCIPAL_GROUP = "group";
-
- /**
- * Kerberos-env configuration property name: password_chat_timeout
- */
- public final static String KERBEROS_ENV_PASSWORD_CHAT_TIMEOUT = "password_chat_timeout";
-
- /**
- * Default timeout for password chat
- */
- public final static int DEFAULT_PASSWORD_CHAT_TIMEOUT = 5;
-
- /**
- * Kerberos-env configuration property name: set_password_expiry
- */
- public final static String KERBEROS_ENV_SET_PASSWORD_EXPIRY = "set_password_expiry";
+ public final static String KERBEROS_ENV_USER_PRINCIPAL_GROUP = "ipa_user_group";
/**
* Kerberos-env configuration property name: ad_create_attributes_template
@@ -232,16 +217,26 @@ public abstract class KerberosOperationHandler {
* @param defaultRealm a String declaring the default Kerberos realm (or domain)
* @param kerberosConfiguration a Map of key/value pairs containing data from the kerberos-env configuration set
*/
- public abstract void open(PrincipalKeyCredential administratorCredential, String defaultRealm, Map<String, String> kerberosConfiguration)
- throws KerberosOperationException;
+ public void open(PrincipalKeyCredential administratorCredential, String defaultRealm, Map<String, String> kerberosConfiguration)
+ throws KerberosOperationException {
+
+ setAdministratorCredential(administratorCredential);
+ setDefaultRealm(defaultRealm);
+
+ if (kerberosConfiguration != null) {
+ setKeyEncryptionTypes(translateEncryptionTypes(kerberosConfiguration.get(KERBEROS_ENV_ENCRYPTION_TYPES), "\\s+"));
+ setExecutableSearchPaths(kerberosConfiguration.get(KERBEROS_ENV_EXECUTABLE_SEARCH_PATHS));
+ }
+ }
/**
* Closes and cleans up any resources used by this KerberosOperationHandler
* <p/>
* It is expected that this KerberosOperationHandler will not be used after this call.
*/
- public abstract void close()
- throws KerberosOperationException;
+ public void close() throws KerberosOperationException {
+ setOpen(false);
+ }
/**
* Test to see if the specified principal exists in a previously configured KDC
@@ -249,10 +244,11 @@ public abstract class KerberosOperationHandler {
* The implementation is specific to a particular type of KDC.
*
* @param principal a String containing the principal to test
+ * @param service a boolean value indicating whether the principal is for a service or not
* @return true if the principal exists; false otherwise
* @throws KerberosOperationException
*/
- public abstract boolean principalExists(String principal)
+ public abstract boolean principalExists(String principal, boolean service)
throws KerberosOperationException;
/**
@@ -277,11 +273,12 @@ public abstract class KerberosOperationHandler {
*
* @param principal a String containing the principal to update
* @param password a String containing the password to set
+ * @param service a boolean value indicating whether the principal is for a service or not
* @return an Integer declaring the new key number
* @throws KerberosOperationException
* @throws KerberosPrincipalDoesNotExistException if the principal does not exist
*/
- public abstract Integer setPrincipalPassword(String principal, String password)
+ public abstract Integer setPrincipalPassword(String principal, String password, boolean service)
throws KerberosOperationException;
/**
@@ -290,10 +287,11 @@ public abstract class KerberosOperationHandler {
* The implementation is specific to a particular type of KDC.
*
* @param principal a String containing the principal to remove
+ * @param service a boolean value indicating whether the principal is for a service or not
* @return true if the principal was successfully removed; otherwise false
* @throws KerberosOperationException
*/
- public abstract boolean removePrincipal(String principal)
+ public abstract boolean removePrincipal(String principal, boolean service)
throws KerberosOperationException;
/**
@@ -313,7 +311,7 @@ public abstract class KerberosOperationHandler {
if (credential == null) {
throw new KerberosOperationException("Missing KDC administrator credential");
} else {
- return principalExists(credential.getPrincipal());
+ return principalExists(credential.getPrincipal(), false);
}
}
@@ -568,11 +566,11 @@ public abstract class KerberosOperationHandler {
* @param keyEncryptionTypes a Set of EncryptionKey values or null to indicate the default set
*/
public void setKeyEncryptionTypes(Set<EncryptionType> keyEncryptionTypes) {
- this.keyEncryptionTypes = new HashSet<>(
- (keyEncryptionTypes == null)
- ? DEFAULT_CIPHERS
- : keyEncryptionTypes
- );
+ this.keyEncryptionTypes = Collections.unmodifiableSet(new HashSet<>(
+ (keyEncryptionTypes == null)
+ ? DEFAULT_CIPHERS
+ : keyEncryptionTypes
+ ));
}
@@ -713,8 +711,8 @@ public abstract class KerberosOperationHandler {
* <p/>
* See {@link org.apache.ambari.server.utils.ShellCommandUtil#runCommand(String[], Map<String,String>)}
*
- * @param command an array of String value representing the command and its arguments
- * @param envp a map of string, string of environment variables
+ * @param command an array of String value representing the command and its arguments
+ * @param envp a map of string, string of environment variables
* @param interactiveHandler a handler to provide responses to queries from the command,
* or null if no queries are expected
* @return a ShellCommandUtil.Result declaring the result of the operation
@@ -751,7 +749,7 @@ public abstract class KerberosOperationHandler {
* @see #executeCommand(String[], Map, ShellCommandUtil.InteractiveHandler)
*/
protected ShellCommandUtil.Result executeCommand(String[] command)
- throws KerberosOperationException {
+ throws KerberosOperationException {
return executeCommand(command, null);
}
@@ -760,7 +758,7 @@ public abstract class KerberosOperationHandler {
* <p/>
* See {@link org.apache.ambari.server.utils.ShellCommandUtil#runCommand(String[])}
*
- * @param command an array of String value representing the command and its arguments
+ * @param command an array of String value representing the command and its arguments
* @param interactiveHandler a handler to provide responses to queries from the command,
* or null if no queries are expected
* @return a ShellCommandUtil.Result declaring the result of the operation
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java
index 1b0f4fb..ff5f5ce 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java
@@ -22,14 +22,18 @@ import static org.apache.ambari.server.serveraction.kerberos.KerberosIdentityDat
import java.io.File;
import java.io.IOException;
+import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
+import java.util.Set;
import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.actionmanager.HostRoleStatus;
import org.apache.ambari.server.agent.CommandReport;
import org.apache.ambari.server.agent.ExecutionCommand;
import org.apache.ambari.server.controller.KerberosHelper;
+import org.apache.ambari.server.orm.dao.HostDAO;
+import org.apache.ambari.server.orm.entities.HostEntity;
import org.apache.ambari.server.security.credential.PrincipalKeyCredential;
import org.apache.ambari.server.serveraction.AbstractServerAction;
import org.apache.ambari.server.state.Cluster;
@@ -40,6 +44,7 @@ import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.reflect.TypeToken;
import com.google.inject.Inject;
/**
@@ -171,6 +176,8 @@ public abstract class KerberosServerAction extends AbstractServerAction {
@Inject
private KerberosHelper kerberosHelper;
+ @Inject
+ HostDAO hostDAO;
/**
* Given a (command parameter) Map and a property name, attempts to safely retrieve the requested
* data.
@@ -543,21 +550,8 @@ public abstract class KerberosServerAction extends AbstractServerAction {
if (record != null) {
String principal = record.get(KerberosIdentityDataFileReader.PRINCIPAL);
-
if (principal != null) {
- String hostname = record.get(KerberosIdentityDataFileReader.HOSTNAME);
-
- if(KerberosHelper.AMBARI_SERVER_HOST_NAME.equals(hostname)) {
- // Replace KerberosHelper.AMBARI_SERVER_HOST_NAME with the actual hostname where the Ambari
- // server is... this host
- hostname = StageUtils.getHostName();
- }
-
- // Evaluate the principal "pattern" found in the record to generate the "evaluated principal"
- // by replacing the _HOST and _REALM variables.
- String evaluatedPrincipal = principal.replace("_HOST", hostname).replace("_REALM", defaultRealm);
-
- commandReport = processIdentity(record, evaluatedPrincipal, operationHandler, kerberosConfiguration, requestSharedDataContext);
+ commandReport = processIdentity(record, principal, operationHandler, kerberosConfiguration, requestSharedDataContext);
}
}
@@ -588,6 +582,32 @@ public abstract class KerberosServerAction extends AbstractServerAction {
}
}
+
+ protected Set<String> getHostFilter() {
+ String serializedValue = getCommandParameterValue(HOST_FILTER);
+
+ if (serializedValue != null) {
+ Type type = new TypeToken<Set<String>>() {
+ }.getType();
+ return StageUtils.getGson().fromJson(serializedValue, type);
+ } else {
+ return null;
+ }
+ }
+
+ protected boolean hasHostFilters() {
+ Set<String> hostFilers = getHostFilter();
+ return hostFilers != null && hostFilers.size() > 0;
+ }
+
+ protected Long ambariServerHostID(){
+ String ambariServerHostName = StageUtils.getHostName();
+ HostEntity ambariServerHostEntity = hostDAO.findByName(ambariServerHostName);
+ return (ambariServerHostEntity == null)
+ ? null
+ : ambariServerHostEntity.getHostId();
+ }
+
/**
* A Kerberos operation type
* <ul>