http://git-wip-us.apache.org/repos/asf/ambari/blob/67fc4a37/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 5ec4c10..a803dcf 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 @@ -34,10 +34,11 @@ import org.apache.ambari.server.configuration.Configuration; import org.apache.ambari.server.controller.KerberosHelper; import org.apache.ambari.server.orm.dao.HostDAO; import org.apache.ambari.server.orm.dao.KerberosPrincipalDAO; -import org.apache.ambari.server.orm.dao.KerberosPrincipalHostDAO; -import org.apache.ambari.server.orm.entities.HostEntity; import org.apache.ambari.server.orm.entities.KerberosPrincipalEntity; import org.apache.ambari.server.serveraction.ActionLog; +import org.apache.ambari.server.serveraction.kerberos.stageutils.KerberosKeytabController; +import org.apache.ambari.server.serveraction.kerberos.stageutils.ResolvedKerberosKeytab; +import org.apache.ambari.server.serveraction.kerberos.stageutils.ResolvedKerberosPrincipal; import org.apache.commons.codec.digest.DigestUtils; import org.apache.directory.server.kerberos.shared.keytab.Keytab; import org.slf4j.Logger; @@ -52,7 +53,7 @@ import com.google.inject.Inject; * This class mainly relies on the KerberosServerAction to iterate through metadata identifying * the Kerberos keytab files that need to be created. For each identity in the metadata, this * implementation's - * {@link KerberosServerAction#processIdentity(Map, String, KerberosOperationHandler, Map, Map)} + * {@link KerberosServerAction#processIdentity(ResolvedKerberosPrincipal, KerberosOperationHandler, Map, Map)} * is invoked attempting the creation of the relevant keytab file. */ public class CreateKeytabFilesServerAction extends KerberosServerAction { @@ -65,12 +66,6 @@ public class CreateKeytabFilesServerAction extends KerberosServerAction { private KerberosPrincipalDAO kerberosPrincipalDAO; /** - * KerberosPrincipalHostDAO used to get Kerberos principal details - */ - @Inject - private KerberosPrincipalHostDAO kerberosPrincipalHostDAO; - - /** * Configuration used to get the configured properties such as the keytab file cache directory */ @Inject @@ -82,6 +77,9 @@ public class CreateKeytabFilesServerAction extends KerberosServerAction { @Inject private HostDAO hostDAO; + @Inject + private KerberosKeytabController kerberosKeytabController; + /** * A map of data used to track what has been processed in order to optimize the creation of keytabs * such as knowing when to create a cached keytab file or use a cached keytab file. @@ -118,10 +116,7 @@ public class CreateKeytabFilesServerAction extends KerberosServerAction { * If a password exists for the current evaluatedPrincipal, use a * {@link org.apache.ambari.server.serveraction.kerberos.KerberosOperationHandler} to generate * the keytab file. To help avoid filename collisions and to build a structure that is easy to - * discover, each keytab file is stored in host-specific - * ({@link org.apache.ambari.server.serveraction.kerberos.KerberosIdentityDataFileReader#HOSTNAME}) - * directory using the SHA1 hash of its destination file path - * ({@link org.apache.ambari.server.serveraction.kerberos.KerberosIdentityDataFileReader#KEYTAB_FILE_PATH}) + * discover, each keytab file is stored in host-specific directory using the SHA1 hash of its destination file path. * <p/> * <pre> * data_directory @@ -133,8 +128,7 @@ public class CreateKeytabFilesServerAction extends KerberosServerAction { * | |- ... * </pre> * - * @param identityRecord a Map containing the data for the current identity record - * @param evaluatedPrincipal a String indicating the relevant principal + * @param resolvedPrincipal a ResolvedKerberosPrincipal object to process * @param operationHandler a KerberosOperationHandler used to perform Kerberos-related * tasks for specific Kerberos implementations * (MIT, Active Directory, etc...) @@ -145,7 +139,7 @@ public class CreateKeytabFilesServerAction extends KerberosServerAction { * @throws AmbariException if an error occurs while processing the identity record */ @Override - protected CommandReport processIdentity(Map<String, String> identityRecord, String evaluatedPrincipal, + protected CommandReport processIdentity(ResolvedKerberosPrincipal resolvedPrincipal, KerberosOperationHandler operationHandler, Map<String, String> kerberosConfiguration, Map<String, Object> requestSharedDataContext) @@ -160,40 +154,42 @@ public class CreateKeytabFilesServerAction extends KerberosServerAction { CommandReport commandReport = null; String message = null; - try { - if (identityRecord != null) { - String dataDirectory = getDataDirectoryPath(); - if (operationHandler == null) { - message = String.format("Failed to create keytab file for %s, missing KerberosOperationHandler", evaluatedPrincipal); - actionLog.writeStdErr(message); - LOG.error(message); - commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr()); - } else if (dataDirectory == null) { - message = "The data directory has not been set. Generated keytab files can not be stored."; - LOG.error(message); - commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr()); - } else { - Map<String, String> principalPasswordMap = getPrincipalPasswordMap(requestSharedDataContext); - Map<String, Integer> principalKeyNumberMap = getPrincipalKeyNumberMap(requestSharedDataContext); + Set<ResolvedKerberosKeytab> keytabsToCreate = kerberosKeytabController.getFromPrincipal(resolvedPrincipal); - String hostName = identityRecord.get(KerberosIdentityDataFileReader.HOSTNAME); - String keytabFilePath = identityRecord.get(KerberosIdentityDataFileReader.KEYTAB_FILE_PATH); + try { + String dataDirectory = getDataDirectoryPath(); + + if (operationHandler == null) { + message = String.format("Failed to create keytab file for %s, missing KerberosOperationHandler", resolvedPrincipal.getPrincipal()); + actionLog.writeStdErr(message); + LOG.error(message); + commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr()); + } else if (dataDirectory == null) { + message = "The data directory has not been set. Generated keytab files can not be stored."; + LOG.error(message); + commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr()); + } else { + Map<String, String> principalPasswordMap = getPrincipalPasswordMap(requestSharedDataContext); + Map<String, Integer> principalKeyNumberMap = getPrincipalKeyNumberMap(requestSharedDataContext); + for (ResolvedKerberosKeytab rkk : keytabsToCreate) { + String hostName = resolvedPrincipal.getHostName(); + String keytabFilePath = rkk.getFile(); if ((hostName != null) && !hostName.isEmpty() && (keytabFilePath != null) && !keytabFilePath.isEmpty()) { - Set<String> visitedPrincipalKeys = visitedIdentities.get(evaluatedPrincipal); + Set<String> visitedPrincipalKeys = visitedIdentities.get(resolvedPrincipal.getPrincipal()); String visitationKey = String.format("%s|%s", hostName, keytabFilePath); if ((visitedPrincipalKeys == null) || !visitedPrincipalKeys.contains(visitationKey)) { // Look up the current evaluatedPrincipal's password. // If found create the keytab file, else try to find it in the cache. - String password = principalPasswordMap.get(evaluatedPrincipal); - Integer keyNumber = principalKeyNumberMap.get(evaluatedPrincipal); + String password = principalPasswordMap.get(resolvedPrincipal.getPrincipal()); + Integer keyNumber = principalKeyNumberMap.get(resolvedPrincipal.getPrincipal()); - message = String.format("Creating keytab file for %s on host %s", evaluatedPrincipal, hostName); + message = String.format("Creating keytab file for %s on host %s", resolvedPrincipal.getPrincipal(), hostName); LOG.info(message); actionLog.writeStdOut(message); - auditEventBuilder.withPrincipal(evaluatedPrincipal).withHostName(hostName).withKeyTabFilePath(keytabFilePath); + auditEventBuilder.withPrincipal(resolvedPrincipal.getPrincipal()).withHostName(hostName).withKeyTabFilePath(keytabFilePath); // Determine where to store the keytab file. It should go into a host-specific // directory under the previously determined data directory. @@ -206,32 +202,22 @@ public class CreateKeytabFilesServerAction extends KerberosServerAction { } if (hostDirectory.exists()) { - File destinationKeytabFile = new File(hostDirectory, DigestUtils.sha1Hex(keytabFilePath)); - HostEntity hostEntity = hostDAO.findByName(hostName); - // in case of ambari-server identity there's no host entity for ambari_server host - if (hostEntity == null && !hostName.equalsIgnoreCase(KerberosHelper.AMBARI_SERVER_HOST_NAME)) { - message = "Failed to find HostEntity for hostname = " + hostName; - actionLog.writeStdErr(message); - LOG.error(message); - commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr()); - return commandReport; - } + File destinationKeytabFile = new File(hostDirectory, DigestUtils.sha256Hex(keytabFilePath)); boolean regenerateKeytabs = getOperationType(getCommandParameters()) == OperationType.RECREATE_ALL; - KerberosPrincipalEntity principalEntity = kerberosPrincipalDAO.find(evaluatedPrincipal); + KerberosPrincipalEntity principalEntity = kerberosPrincipalDAO.find(resolvedPrincipal.getPrincipal()); String cachedKeytabPath = (principalEntity == null) ? null : principalEntity.getCachedKeytabPath(); if (password == null) { - if (!regenerateKeytabs && (hostName.equalsIgnoreCase(KerberosHelper.AMBARI_SERVER_HOST_NAME) || kerberosPrincipalHostDAO - .exists(evaluatedPrincipal, hostEntity.getHostId(), keytabFilePath)) && cachedKeytabPath == null) { + if (!regenerateKeytabs && hostName.equalsIgnoreCase(KerberosHelper.AMBARI_SERVER_HOST_NAME)) { // There is nothing to do for this since it must already exist and we don't want to // regenerate the keytab - message = String.format("Skipping keytab file for %s, missing password indicates nothing to do", evaluatedPrincipal); + message = String.format("Skipping keytab file for %s, missing password indicates nothing to do", resolvedPrincipal.getPrincipal()); LOG.debug(message); } else { if (cachedKeytabPath == null) { - message = String.format("Failed to create keytab for %s, missing cached file", evaluatedPrincipal); + message = String.format("Failed to create keytab for %s, missing cached file", resolvedPrincipal.getPrincipal()); actionLog.writeStdErr(message); LOG.error(message); commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr()); @@ -239,7 +225,7 @@ public class CreateKeytabFilesServerAction extends KerberosServerAction { try { operationHandler.createKeytabFile(new File(cachedKeytabPath), destinationKeytabFile); } catch (KerberosOperationException e) { - message = String.format("Failed to create keytab file for %s - %s", evaluatedPrincipal, e.getMessage()); + message = String.format("Failed to create keytab file for %s - %s", resolvedPrincipal.getPrincipal(), e.getMessage()); actionLog.writeStdErr(message); LOG.error(message, e); commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr()); @@ -247,24 +233,24 @@ public class CreateKeytabFilesServerAction extends KerberosServerAction { } } } else { - Keytab keytab = createKeytab(evaluatedPrincipal, password, keyNumber, operationHandler, visitedPrincipalKeys != null, true, actionLog); + Keytab keytab = createKeytab(resolvedPrincipal.getPrincipal(), password, keyNumber, operationHandler, visitedPrincipalKeys != null, true, actionLog); if (keytab != null) { try { if (operationHandler.createKeytabFile(keytab, destinationKeytabFile)) { ensureAmbariOnlyAccess(destinationKeytabFile); - message = String.format("Successfully created keytab file for %s at %s", evaluatedPrincipal, destinationKeytabFile.getAbsolutePath()); + message = String.format("Successfully created keytab file for %s at %s", resolvedPrincipal.getPrincipal(), destinationKeytabFile.getAbsolutePath()); LOG.debug(message); - auditEventBuilder.withPrincipal(evaluatedPrincipal).withHostName(hostName).withKeyTabFilePath(destinationKeytabFile.getAbsolutePath()); + auditEventBuilder.withPrincipal(resolvedPrincipal.getPrincipal()).withHostName(hostName).withKeyTabFilePath(destinationKeytabFile.getAbsolutePath()); } else { - message = String.format("Failed to create keytab file for %s at %s", evaluatedPrincipal, destinationKeytabFile.getAbsolutePath()); + message = String.format("Failed to create keytab file for %s at %s", resolvedPrincipal.getPrincipal(), destinationKeytabFile.getAbsolutePath()); actionLog.writeStdErr(message); LOG.error(message); commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr()); } } catch (KerberosOperationException e) { - message = String.format("Failed to create keytab file for %s - %s", evaluatedPrincipal, e.getMessage()); + message = String.format("Failed to create keytab file for %s - %s", resolvedPrincipal.getPrincipal(), e.getMessage()); actionLog.writeStdErr(message); LOG.error(message, e); commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr()); @@ -275,20 +261,20 @@ public class CreateKeytabFilesServerAction extends KerberosServerAction { if (visitedPrincipalKeys == null) { visitedPrincipalKeys = new HashSet<>(); - visitedIdentities.put(evaluatedPrincipal, visitedPrincipalKeys); + visitedIdentities.put(resolvedPrincipal.getPrincipal(), visitedPrincipalKeys); } visitedPrincipalKeys.add(visitationKey); } } else { message = String.format("Failed to create keytab file for %s, the container directory does not exist: %s", - evaluatedPrincipal, hostDirectory.getAbsolutePath()); + resolvedPrincipal.getPrincipal(), hostDirectory.getAbsolutePath()); actionLog.writeStdErr(message); LOG.error(message); commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr()); } } else { - LOG.debug("Skipping previously processed keytab for {} on host {}", evaluatedPrincipal, hostName); + LOG.debug("Skipping previously processed keytab for {} on host {}", resolvedPrincipal.getPrincipal(), hostName); } } } @@ -420,7 +406,7 @@ public class CreateKeytabFilesServerAction extends KerberosServerAction { } } - File cachedKeytabFile = new File(cacheDirectory, DigestUtils.sha1Hex(principal + String.valueOf(System.currentTimeMillis()))); + File cachedKeytabFile = new File(cacheDirectory, DigestUtils.sha256Hex(principal + String.valueOf(System.currentTimeMillis()))); try { keytab.write(cachedKeytabFile);
http://git-wip-us.apache.org/repos/asf/ambari/blob/67fc4a37/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 0c90659..a108c9b 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 @@ -28,12 +28,13 @@ 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.audit.event.kerberos.CreatePrincipalKerberosAuditEvent; +import org.apache.ambari.server.orm.dao.KerberosKeytabPrincipalDAO; import org.apache.ambari.server.orm.dao.KerberosPrincipalDAO; -import org.apache.ambari.server.orm.dao.KerberosPrincipalHostDAO; +import org.apache.ambari.server.orm.entities.KerberosKeytabPrincipalEntity; import org.apache.ambari.server.orm.entities.KerberosPrincipalEntity; -import org.apache.ambari.server.orm.entities.KerberosPrincipalHostEntity; import org.apache.ambari.server.security.SecurePasswordHelper; import org.apache.ambari.server.serveraction.ActionLog; +import org.apache.ambari.server.serveraction.kerberos.stageutils.ResolvedKerberosPrincipal; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -45,7 +46,7 @@ import com.google.inject.Inject; * <p/> * This class mainly relies on the KerberosServerAction to iterate through metadata identifying * the Kerberos principals that need to be created. For each identity in the metadata, this implementation's - * {@link KerberosServerAction#processIdentity(Map, String, KerberosOperationHandler, Map, Map)} + * {@link KerberosServerAction#processIdentity(ResolvedKerberosPrincipal, KerberosOperationHandler, Map, Map)} * is invoked attempting the creation of the relevant principal. */ public class CreatePrincipalsServerAction extends KerberosServerAction { @@ -58,17 +59,14 @@ public class CreatePrincipalsServerAction extends KerberosServerAction { private KerberosPrincipalDAO kerberosPrincipalDAO; /** - * KerberosPrincipalHostDAO used to get Kerberos principal details - */ - @Inject - private KerberosPrincipalHostDAO kerberosPrincipalHostDAO; - - /** * SecurePasswordHelper used to generate secure passwords for newly created principals */ @Inject private SecurePasswordHelper securePasswordHelper; + @Inject + private KerberosKeytabPrincipalDAO kerberosKeytabPrincipalDAO; + /** * A set of visited principal names used to prevent unnecessary processing on already processed * principal names @@ -106,8 +104,7 @@ public class CreatePrincipalsServerAction extends KerberosServerAction { * store the new key numbers in the shared principal-to-key_number map so that subsequent process * may use the data if necessary. * - * @param identityRecord a Map containing the data for the current identity record - * @param evaluatedPrincipal a String indicating the relevant principal + * @param resolvedPrincipal a ResolvedKerberosPrincipal object to process * @param operationHandler a KerberosOperationHandler used to perform Kerberos-related * tasks for specific Kerberos implementations * (MIT, Active Directory, etc...) @@ -118,7 +115,7 @@ public class CreatePrincipalsServerAction extends KerberosServerAction { * @throws AmbariException if an error occurs while processing the identity record */ @Override - protected CommandReport processIdentity(Map<String, String> identityRecord, String evaluatedPrincipal, + protected CommandReport processIdentity(ResolvedKerberosPrincipal resolvedPrincipal, KerberosOperationHandler operationHandler, Map<String, String> kerberosConfiguration, Map<String, Object> requestSharedDataContext) @@ -126,16 +123,16 @@ public class CreatePrincipalsServerAction extends KerberosServerAction { CommandReport commandReport = null; // Only process this principal name if we haven't already processed it - if (!seenPrincipals.contains(evaluatedPrincipal)) { - seenPrincipals.add(evaluatedPrincipal); + // TODO optimize - split invalidation and principal creation to separate stages + if (!seenPrincipals.contains(resolvedPrincipal.getPrincipal())) { + seenPrincipals.add(resolvedPrincipal.getPrincipal()); boolean processPrincipal; - // TODO add invalidate_principals option to make keytabs invalid all over the cluster. - KerberosPrincipalEntity kerberosPrincipalEntity = kerberosPrincipalDAO.find(evaluatedPrincipal); + KerberosPrincipalEntity kerberosPrincipalEntity = kerberosPrincipalDAO.find(resolvedPrincipal.getPrincipal()); boolean regenerateKeytabs = getOperationType(getCommandParameters()) == OperationType.RECREATE_ALL; - boolean servicePrincipal = "service".equalsIgnoreCase(identityRecord.get(KerberosIdentityDataFileReader.PRINCIPAL_TYPE)); + boolean servicePrincipal = resolvedPrincipal.isService(); if (regenerateKeytabs) { // force recreation of principal due to keytab regeneration // regenerate only service principals if request filtered by hosts @@ -154,24 +151,24 @@ public class CreatePrincipalsServerAction extends KerberosServerAction { if (processPrincipal) { Map<String, String> principalPasswordMap = getPrincipalPasswordMap(requestSharedDataContext); - String password = principalPasswordMap.get(evaluatedPrincipal); + String password = principalPasswordMap.get(resolvedPrincipal.getPrincipal()); if (password == null) { - CreatePrincipalResult result = createPrincipal(evaluatedPrincipal, servicePrincipal, kerberosConfiguration, operationHandler, regenerateKeytabs, actionLog); + CreatePrincipalResult result = createPrincipal(resolvedPrincipal.getPrincipal(), servicePrincipal, kerberosConfiguration, operationHandler, regenerateKeytabs, actionLog); if (result == null) { commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr()); } else { Map<String, Integer> principalKeyNumberMap = getPrincipalKeyNumberMap(requestSharedDataContext); - principalPasswordMap.put(evaluatedPrincipal, result.getPassword()); - principalKeyNumberMap.put(evaluatedPrincipal, result.getKeyNumber()); + principalPasswordMap.put(resolvedPrincipal.getPrincipal(), result.getPassword()); + principalKeyNumberMap.put(resolvedPrincipal.getPrincipal(), result.getKeyNumber()); // invalidate given principal for all keytabs to make them redistributed again - for (KerberosPrincipalHostEntity kphe: kerberosPrincipalHostDAO.findByPrincipal(evaluatedPrincipal)) { - kphe.setDistributed(false); - kerberosPrincipalHostDAO.merge(kphe); + for (KerberosKeytabPrincipalEntity kkpe: kerberosKeytabPrincipalDAO.findByPrincipal(resolvedPrincipal.getPrincipal())) { + kkpe.setDistributed(false); + kerberosKeytabPrincipalDAO.merge(kkpe); } // invalidate principal cache - KerberosPrincipalEntity principalEntity = kerberosPrincipalDAO.find(evaluatedPrincipal); + KerberosPrincipalEntity principalEntity = kerberosPrincipalDAO.find(resolvedPrincipal.getPrincipal()); try { new File(principalEntity.getCachedKeytabPath()).delete(); } catch (Exception e) { http://git-wip-us.apache.org/repos/asf/ambari/blob/67fc4a37/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/DestroyPrincipalsServerAction.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/DestroyPrincipalsServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/DestroyPrincipalsServerAction.java index 4c80bd4..7c28494 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/DestroyPrincipalsServerAction.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/DestroyPrincipalsServerAction.java @@ -29,8 +29,13 @@ import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.agent.CommandReport; import org.apache.ambari.server.audit.event.kerberos.DestroyPrincipalKerberosAuditEvent; import org.apache.ambari.server.controller.KerberosHelper; +import org.apache.ambari.server.orm.dao.KerberosKeytabDAO; +import org.apache.ambari.server.orm.dao.KerberosKeytabPrincipalDAO; import org.apache.ambari.server.orm.dao.KerberosPrincipalDAO; +import org.apache.ambari.server.orm.entities.KerberosKeytabEntity; import org.apache.ambari.server.orm.entities.KerberosPrincipalEntity; +import org.apache.ambari.server.serveraction.kerberos.stageutils.ResolvedKerberosKeytab; +import org.apache.ambari.server.serveraction.kerberos.stageutils.ResolvedKerberosPrincipal; import org.apache.ambari.server.utils.ShellCommandUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,7 +48,7 @@ import com.google.inject.Inject; * This class mainly relies on the KerberosServerAction to iterate through metadata identifying * the Kerberos principals that need to be removed from the relevant KDC. For each identity in the * metadata, this implementation's - * {@link KerberosServerAction#processIdentity(Map, String, KerberosOperationHandler, Map, Map)} + * {@link KerberosServerAction#processIdentity(ResolvedKerberosPrincipal, KerberosOperationHandler, Map, Map)} * is invoked attempting the removal of the relevant principal. */ public class DestroyPrincipalsServerAction extends KerberosServerAction { @@ -52,6 +57,12 @@ public class DestroyPrincipalsServerAction extends KerberosServerAction { @Inject private KerberosPrincipalDAO kerberosPrincipalDAO; + @Inject + private KerberosKeytabPrincipalDAO kerberosKeytabPrincipalDAO; + + @Inject + private KerberosKeytabDAO kerberosKeytabDAO; + /** * A set of visited principal names used to prevent unnecessary processing on already processed * principal names @@ -81,8 +92,7 @@ public class DestroyPrincipalsServerAction extends KerberosServerAction { /** * For each identity, remove the principal from the configured KDC. * - * @param identityRecord a Map containing the data for the current identity record - * @param evaluatedPrincipal a String indicating the relevant principal + * @param resolvedPrincipal a ResolvedKerberosPrincipal object to process * @param operationHandler a KerberosOperationHandler used to perform Kerberos-related * tasks for specific Kerberos implementations * (MIT, Active Directory, etc...) @@ -93,69 +103,73 @@ public class DestroyPrincipalsServerAction extends KerberosServerAction { * @throws org.apache.ambari.server.AmbariException if an error occurs while processing the identity record */ @Override - protected CommandReport processIdentity(Map<String, String> identityRecord, String evaluatedPrincipal, + protected CommandReport processIdentity(ResolvedKerberosPrincipal resolvedPrincipal, KerberosOperationHandler operationHandler, Map<String, String> kerberosConfiguration, Map<String, Object> requestSharedDataContext) throws AmbariException { // Only process this principal if we haven't already processed it - if (!seenPrincipals.contains(evaluatedPrincipal)) { - seenPrincipals.add(evaluatedPrincipal); + if (!seenPrincipals.contains(resolvedPrincipal.getPrincipal())) { + seenPrincipals.add(resolvedPrincipal.getPrincipal()); - String message = String.format("Destroying identity, %s", evaluatedPrincipal); + String message = String.format("Destroying identity, %s", resolvedPrincipal.getPrincipal()); LOG.info(message); actionLog.writeStdOut(message); DestroyPrincipalKerberosAuditEvent.DestroyPrincipalKerberosAuditEventBuilder auditEventBuilder = DestroyPrincipalKerberosAuditEvent.builder() .withTimestamp(System.currentTimeMillis()) .withRequestId(getHostRoleCommand().getRequestId()) .withTaskId(getHostRoleCommand().getTaskId()) - .withPrincipal(evaluatedPrincipal); + .withPrincipal(resolvedPrincipal.getPrincipal()); try { try { - boolean servicePrincipal = "service".equalsIgnoreCase(identityRecord.get(KerberosIdentityDataFileReader.PRINCIPAL_TYPE)); - operationHandler.removePrincipal(evaluatedPrincipal, servicePrincipal); + boolean servicePrincipal = resolvedPrincipal.isService(); + operationHandler.removePrincipal(resolvedPrincipal.getPrincipal(), servicePrincipal); } catch (KerberosOperationException e) { - message = String.format("Failed to remove identity for %s from the KDC - %s", evaluatedPrincipal, e.getMessage()); + message = String.format("Failed to remove identity for %s from the KDC - %s", resolvedPrincipal.getPrincipal(), e.getMessage()); LOG.warn(message); actionLog.writeStdErr(message); auditEventBuilder.withReasonOfFailure(message); } try { - KerberosPrincipalEntity principalEntity = kerberosPrincipalDAO.find(evaluatedPrincipal); + KerberosPrincipalEntity principalEntity = kerberosPrincipalDAO.find(resolvedPrincipal.getPrincipal()); if (principalEntity != null) { String cachedKeytabPath = principalEntity.getCachedKeytabPath(); - + KerberosKeytabEntity kke = kerberosKeytabDAO.find(resolvedPrincipal.getResolvedKerberosKeytab().getFile()); + kerberosKeytabDAO.remove(kke); kerberosPrincipalDAO.remove(principalEntity); // If a cached keytabs file exists for this principal, delete it. if (cachedKeytabPath != null) { if (!new File(cachedKeytabPath).delete()) { - LOG.debug("Failed to remove cached keytab for {}", evaluatedPrincipal); + LOG.debug("Failed to remove cached keytab for {}", resolvedPrincipal.getPrincipal()); } } } // delete Ambari server keytab - String hostName = identityRecord.get(KerberosIdentityDataFileReader.HOSTNAME); + String hostName = resolvedPrincipal.getHostName(); if (hostName != null && hostName.equalsIgnoreCase(KerberosHelper.AMBARI_SERVER_HOST_NAME)) { - String keytabFilePath = identityRecord.get(KerberosIdentityDataFileReader.KEYTAB_FILE_PATH); - if (keytabFilePath != null) { - try { - ShellCommandUtil.Result result = ShellCommandUtil.delete(keytabFilePath, true, true); - if (!result.isSuccessful()) { - LOG.warn("Failed to remove ambari keytab for {} due to {}", evaluatedPrincipal, result.getStderr()); + ResolvedKerberosKeytab resolvedKeytab = resolvedPrincipal.getResolvedKerberosKeytab(); + if (resolvedKeytab != null) { + String keytabFilePath = resolvedKeytab.getFile(); + if (keytabFilePath != null) { + try { + ShellCommandUtil.Result result = ShellCommandUtil.delete(keytabFilePath, true, true); + if (!result.isSuccessful()) { + LOG.warn("Failed to remove ambari keytab for {} due to {}", resolvedPrincipal.getPrincipal(), result.getStderr()); + } + } catch (IOException|InterruptedException e) { + LOG.warn("Failed to remove ambari keytab for " + resolvedPrincipal.getPrincipal(), e); } - } catch (IOException|InterruptedException e) { - LOG.warn("Failed to remove ambari keytab for " + evaluatedPrincipal, e); } } } } catch (Throwable t) { - message = String.format("Failed to remove identity for %s from the Ambari database - %s", evaluatedPrincipal, t.getMessage()); + message = String.format("Failed to remove identity for %s from the Ambari database - %s", resolvedPrincipal.getPrincipal(), t.getMessage()); LOG.warn(message); actionLog.writeStdErr(message); auditEventBuilder.withReasonOfFailure(message); http://git-wip-us.apache.org/repos/asf/ambari/blob/67fc4a37/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/FinalizeKerberosServerAction.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/FinalizeKerberosServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/FinalizeKerberosServerAction.java index bfd5e40..225e53e 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/FinalizeKerberosServerAction.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/FinalizeKerberosServerAction.java @@ -26,9 +26,10 @@ import java.util.concurrent.ConcurrentMap; 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.serveraction.kerberos.stageutils.ResolvedKerberosPrincipal; import org.apache.ambari.server.utils.ShellCommandUtil; import org.apache.ambari.server.utils.StageUtils; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,8 +44,7 @@ public class FinalizeKerberosServerAction extends KerberosServerAction { * some user accounts and groups may not have been available (at the OS level) when the keytab files * were created. * - * @param identityRecord a Map containing the data for the current identity record - * @param evaluatedPrincipal a String indicating the relevant principal + * @param resolvedPrincipal a ResolvedKerberosPrincipal object to process * @param operationHandler a KerberosOperationHandler used to perform Kerberos-related * tasks for specific Kerberos implementations * (MIT, Active Directory, etc...) @@ -54,39 +54,39 @@ public class FinalizeKerberosServerAction extends KerberosServerAction { * @throws AmbariException */ @Override - protected CommandReport processIdentity(Map<String, String> identityRecord, String evaluatedPrincipal, + protected CommandReport processIdentity(ResolvedKerberosPrincipal resolvedPrincipal, KerberosOperationHandler operationHandler, Map<String, String> kerberosConfiguration, Map<String, Object> requestSharedDataContext) throws AmbariException { - if (identityRecord != null) { + if (resolvedPrincipal != null) { // If the record's HOSTNAME value is "ambari-server", rather than an actual hostname it will // not match the Ambari server's host name. This will occur if the there is no agent installed // on the Ambari server host. This is ok, since any keytab files installed on the Ambari server // host will already have the permissions set so that only the Ambari server can read it. // There is no need to update the permissions for those keytab files so that installed services // can access them since no services will be installed on the host. - if (StageUtils.getHostName().equals(identityRecord.get(KerberosIdentityDataFile.HOSTNAME))) { + if (StageUtils.getHostName().equals(resolvedPrincipal.getHostName())) { // If the principal name exists in one of the shared data maps, it has been processed by the // current "Enable Kerberos" or "Add component" workflow and therefore should already have // the correct permissions assigned. The relevant keytab files can be skipped. Map<String, String> principalPasswordMap = getPrincipalPasswordMap(requestSharedDataContext); - if ((principalPasswordMap == null) || !principalPasswordMap.containsKey(evaluatedPrincipal)) { + if ((principalPasswordMap == null) || !principalPasswordMap.containsKey(resolvedPrincipal.getPrincipal())) { - String keytabFilePath = identityRecord.get(KerberosIdentityDataFile.KEYTAB_FILE_PATH); + String keytabFilePath = resolvedPrincipal.getKeytabPath(); if (!StringUtils.isEmpty(keytabFilePath)) { Set<String> visited = (Set<String>) requestSharedDataContext.get(this.getClass().getName() + "_visited"); if (!visited.contains(keytabFilePath)) { - String ownerName = identityRecord.get(KerberosIdentityDataFile.KEYTAB_FILE_OWNER_NAME); - String ownerAccess = identityRecord.get(KerberosIdentityDataFileReader.KEYTAB_FILE_OWNER_ACCESS); + String ownerName = resolvedPrincipal.getResolvedKerberosKeytab().getOwnerName(); + String ownerAccess = resolvedPrincipal.getResolvedKerberosKeytab().getOwnerAccess(); boolean ownerWritable = "w".equalsIgnoreCase(ownerAccess) || "rw".equalsIgnoreCase(ownerAccess); boolean ownerReadable = "r".equalsIgnoreCase(ownerAccess) || "rw".equalsIgnoreCase(ownerAccess); - String groupName = identityRecord.get(KerberosIdentityDataFile.KEYTAB_FILE_GROUP_NAME); - String groupAccess = identityRecord.get(KerberosIdentityDataFileReader.KEYTAB_FILE_OWNER_ACCESS); + String groupName = resolvedPrincipal.getResolvedKerberosKeytab().getGroupName(); + String groupAccess = resolvedPrincipal.getResolvedKerberosKeytab().getGroupAccess(); boolean groupWritable = "w".equalsIgnoreCase(groupAccess) || "rw".equalsIgnoreCase(groupAccess); boolean groupReadable = "r".equalsIgnoreCase(groupAccess) || "rw".equalsIgnoreCase(groupAccess); http://git-wip-us.apache.org/repos/asf/ambari/blob/67fc4a37/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 ff5f5ce..2c9aa8c 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 @@ -18,11 +18,10 @@ package org.apache.ambari.server.serveraction.kerberos; -import static org.apache.ambari.server.serveraction.kerberos.KerberosIdentityDataFileReader.DATA_FILE_NAME; - import java.io.File; import java.io.IOException; import java.lang.reflect.Type; +import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; @@ -36,6 +35,9 @@ 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.serveraction.kerberos.stageutils.KerberosKeytabController; +import org.apache.ambari.server.serveraction.kerberos.stageutils.ResolvedKerberosKeytab; +import org.apache.ambari.server.serveraction.kerberos.stageutils.ResolvedKerberosPrincipal; import org.apache.ambari.server.state.Cluster; import org.apache.ambari.server.state.Clusters; import org.apache.ambari.server.utils.StageUtils; @@ -178,6 +180,10 @@ public abstract class KerberosServerAction extends AbstractServerAction { @Inject HostDAO hostDAO; + + @Inject + KerberosKeytabController kerberosKeytabController; + /** * Given a (command parameter) Map and a property name, attempts to safely retrieve the requested * data. @@ -235,10 +241,9 @@ public abstract class KerberosServerAction extends AbstractServerAction { */ protected static OperationType getOperationType(Map<String, String> commandParameters) { String value = getCommandParameterValue(commandParameters, OPERATION_TYPE); - if(StringUtils.isEmpty(value)) { + if (StringUtils.isEmpty(value)) { return OperationType.DEFAULT; - } - else { + } else { return OperationType.valueOf(value.toUpperCase()); } } @@ -365,14 +370,32 @@ public abstract class KerberosServerAction extends AbstractServerAction { } /** + * Returns preconfigure type passed to current action. + * + * @return PreconfigureServiceType + */ + protected PreconfigureServiceType getCommandPreconfigureType() { + String preconfigureServices = getCommandParameterValue(getCommandParameters(), PRECONFIGURE_SERVICES); + PreconfigureServiceType type = null; + if (!StringUtils.isEmpty(preconfigureServices)) { + try { + type = PreconfigureServiceType.valueOf(preconfigureServices.toUpperCase()); + } catch (Throwable t) { + LOG.warn("Invalid preconfigure_services value, assuming DEFAULT: {}", preconfigureServices); + type = PreconfigureServiceType.DEFAULT; + } + } + return type; + } + + /** * Iterates through the Kerberos identity metadata from the * {@link org.apache.ambari.server.serveraction.kerberos.KerberosIdentityDataFileReader} and calls * the implementing class to handle each identity found. * <p/> - * Using the "data_directory" value from this action's command parameters map, creates a - * {@link KerberosIdentityDataFileReader} to parse - * the relative identity.dat file and iterate through its "records". Each "record" is process using - * {@link #processRecord(Map, String, KerberosOperationHandler, Map, Map)}. + * Using {@link #getHostFilter()}, {@link #getIdentityFilter()} and {@link #getServiceComponentFilter()} it retrieve + * list of filtered keytabs and their principals and process each principal using + * {@link #processIdentity(ResolvedKerberosPrincipal, KerberosOperationHandler, Map, Map)}. * * @param requestSharedDataContext a Map to be used a shared data among all ServerActions related * to a given request @@ -390,102 +413,43 @@ public abstract class KerberosServerAction extends AbstractServerAction { if (commandParameters != null) { // Grab the relevant data from this action's command parameters map PrincipalKeyCredential administratorCredential = kerberosHelper.getKDCAdministratorCredentials(getClusterName()); - String defaultRealm = getDefaultRealm(commandParameters); KDCType kdcType = getKDCType(commandParameters); - String dataDirectoryPath = getDataDirectoryPath(commandParameters); - - if (dataDirectoryPath != null) { - File dataDirectory = new File(dataDirectoryPath); - - // If the data directory exists, attempt to process further, else assume there is no work to do - if (dataDirectory.exists()) { - if (!dataDirectory.isDirectory() || !dataDirectory.canRead()) { - String message = String.format("Failed to process the identities, the data directory is not accessible: %s", - dataDirectory.getAbsolutePath()); - actionLog.writeStdErr(message); - LOG.error(message); - throw new AmbariException(message); - } - // The "identity data" file may or may not exist in the data directory, depending on if - // there is work to do or not. - File identityDataFile = new File(dataDirectory, DATA_FILE_NAME); - - if (identityDataFile.exists()) { - if (!identityDataFile.canRead()) { - String message = String.format("Failed to process the identities, cannot read the index file: %s", - identityDataFile.getAbsolutePath()); - actionLog.writeStdErr(message); - LOG.error(message); - throw new AmbariException(message); - } - - 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()); - actionLog.writeStdErr(message); - LOG.error(message); - throw new AmbariException(message); - } - - Map<String, String> kerberosConfiguration = getConfiguration("kerberos-env"); + String defaultRealm = getDefaultRealm(commandParameters); - try { - handler.open(administratorCredential, defaultRealm, kerberosConfiguration); - } catch (KerberosOperationException e) { - String message = String.format("Failed to process the identities, could not properly open the KDC operation handler: %s", - e.getMessage()); - actionLog.writeStdErr(message); - LOG.error(message); - throw new AmbariException(message, e); - } + KerberosOperationHandler handler = kerberosOperationHandlerFactory.getKerberosOperationHandler(kdcType); + Map<String, String> kerberosConfiguration = getConfiguration("kerberos-env"); + + try { + handler.open(administratorCredential, defaultRealm, kerberosConfiguration); + } catch (KerberosOperationException e) { + String message = String.format("Failed to process the identities, could not properly open the KDC operation handler: %s", + e.getMessage()); + actionLog.writeStdErr(message); + LOG.error(message); + throw new AmbariException(message, e); + } - // Create the data file reader to parse and iterate through the records - KerberosIdentityDataFileReader reader = null; - try { - reader = kerberosIdentityDataFileReaderFactory.createKerberosIdentityDataFileReader(identityDataFile); - for (Map<String, String> record : reader) { - // Process the current record - commandReport = processRecord(record, defaultRealm, handler, kerberosConfiguration, requestSharedDataContext); - - // If the principal processor returns a CommandReport, than it is time to stop since - // an error condition has probably occurred, else all is assumed to be well. - if (commandReport != null) { - 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 - throw new AmbariException(e.getMessage(), e); - } catch (IOException e) { - String message = String.format("Failed to process the identities, cannot read the index file: %s", - identityDataFile.getAbsolutePath()); - actionLog.writeStdErr(message); - LOG.error(message, e); - throw new AmbariException(message, e); - } finally { - if (reader != null) { - // The reader needs to be closed, if it fails to close ignore the exception since - // there is little we can or care to do about it now. - try { - reader.close(); - } catch (IOException e) { - // Ignore this... - } - } - - // The KerberosOperationHandler needs to be closed, if it fails to close ignore the - // exception since there is little we can or care to do about it now. - try { - handler.close(); - } catch (KerberosOperationException e) { - // Ignore this... - } + try { + for (ResolvedKerberosKeytab rkk : kerberosKeytabController.getFilteredKeytabs((Map<String, Collection<String>>) getServiceComponentFilter(), getHostFilter(), getIdentityFilter())) { + for (ResolvedKerberosPrincipal principal : rkk.getPrincipals()) { + commandReport = processIdentity(principal, handler, kerberosConfiguration, requestSharedDataContext); + // If the principal processor returns a CommandReport, than it is time to stop since + // an error condition has probably occurred, else all is assumed to be well. + if (commandReport != null) { + break; } } } + } finally { + // The KerberosOperationHandler needs to be closed, if it fails to close ignore the + // exception since there is little we can or care to do about it now. + try { + handler.close(); + } catch (KerberosOperationException e) { + // Ignore this... + } } + } actionLog.writeStdOut("Processing identities completed."); @@ -502,11 +466,10 @@ public abstract class KerberosServerAction extends AbstractServerAction { * Processes an identity as necessary. * <p/> * This method is called from {@link #processIdentities(Map)} for each - * identity "record" found in the Kerberos identity metadata file. After processing, it is expected + * principal found by specified filter. After processing, it is expected * that the return value is null on success and a CommandReport (indicating the error) on failure. * - * @param identityRecord a Map containing the data for the current identity record - * @param evaluatedPrincipal a String indicating the relevant principal + * @param resolvedPrincipal a ResolvedKerberosPrincipal object to process * @param operationHandler a KerberosOperationHandler used to perform Kerberos-related * tasks for specific Kerberos implementations * (MIT, Active Directory, etc...) @@ -516,48 +479,12 @@ public abstract class KerberosServerAction extends AbstractServerAction { * condition; or null, indicating a success condition * @throws AmbariException if an error occurs while processing the identity record */ - protected abstract CommandReport processIdentity(Map<String, String> identityRecord, - String evaluatedPrincipal, + protected abstract CommandReport processIdentity(ResolvedKerberosPrincipal resolvedPrincipal, KerberosOperationHandler operationHandler, Map<String, String> kerberosConfiguration, Map<String, Object> requestSharedDataContext) throws AmbariException; - /** - * Process and prepares an identity record to be handled by the implementing class. - * <p/> - * Given the data from the record Map, attempts to replace variables in the principal pattern to - * generate a concrete principal value to further process. This "evaluated principal" is then passed to - * {@link #processIdentity(Map, String, KerberosOperationHandler, Map, Map)} - * to be handled as needed. - * - * @param record a Map containing the data for the current identity record - * @param defaultRealm a String declaring the default Kerberos realm - * @param operationHandler a KerberosOperationHandler used to perform Kerberos-related - * tasks for specific Kerberos implementations - * (MIT, Active Directory, etc...) - * @param kerberosConfiguration a Map of configuration properties from kerberos-env - * @param requestSharedDataContext a Map to be used a shared data among all ServerActions related - * to a given request @return a CommandReport, indicating an error - * condition; or null, indicating a success condition - * @throws AmbariException if an error occurs while processing the identity record - */ - private CommandReport processRecord(Map<String, String> record, String defaultRealm, - KerberosOperationHandler operationHandler, - Map<String, String> kerberosConfiguration, Map<String, Object> requestSharedDataContext) - throws AmbariException { - CommandReport commandReport = null; - - if (record != null) { - String principal = record.get(KerberosIdentityDataFileReader.PRINCIPAL); - if (principal != null) { - commandReport = processIdentity(record, principal, operationHandler, kerberosConfiguration, requestSharedDataContext); - } - } - - return commandReport; - } - protected void deleteDataDirectory(String dataDirectoryPath) { // Make sure this is a relevant directory. We don't want to accidentally allow _ANY_ directory // to be deleted. @@ -600,7 +527,32 @@ public abstract class KerberosServerAction extends AbstractServerAction { return hostFilers != null && hostFilers.size() > 0; } - protected Long ambariServerHostID(){ + + protected Map<String, ? extends Collection<String>> getServiceComponentFilter() { + String serializedValue = getCommandParameterValue(SERVICE_COMPONENT_FILTER); + + if (serializedValue != null) { + Type type = new TypeToken<Map<String, ? extends Collection<String>>>() { + }.getType(); + return StageUtils.getGson().fromJson(serializedValue, type); + } else { + return null; + } + } + + protected Collection<String> getIdentityFilter() { + String serializedValue = getCommandParameterValue(IDENTITY_FILTER); + + if (serializedValue != null) { + Type type = new TypeToken<Collection<String>>() { + }.getType(); + return StageUtils.getGson().fromJson(serializedValue, type); + } else { + return null; + } + } + + protected Long ambariServerHostID() { String ambariServerHostName = StageUtils.getHostName(); HostEntity ambariServerHostEntity = hostDAO.findByName(ambariServerHostName); return (ambariServerHostEntity == null) @@ -608,6 +560,65 @@ public abstract class KerberosServerAction extends AbstractServerAction { : ambariServerHostEntity.getHostId(); } + + public static class KerberosCommandParameters { + private Map<String, String> params; + + public KerberosCommandParameters(ExecutionCommand ec) { + params = ec.getCommandParams(); + } + + public KerberosCommandParameters(AbstractServerAction serverAction) { + this(serverAction.getExecutionCommand()); + } + + public 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; + } + } + + public boolean hasHostFilters() { + Set<String> hostFilers = getHostFilter(); + return hostFilers != null && hostFilers.size() > 0; + } + + public Map<String, ? extends Collection<String>> getServiceComponentFilter() { + String serializedValue = getCommandParameterValue(SERVICE_COMPONENT_FILTER); + + if (serializedValue != null) { + Type type = new TypeToken<Map<String, ? extends Collection<String>>>() { + }.getType(); + return StageUtils.getGson().fromJson(serializedValue, type); + } else { + return null; + } + } + + public Collection<String> getIdentityFilter() { + String serializedValue = getCommandParameterValue(IDENTITY_FILTER); + + if (serializedValue != null) { + Type type = new TypeToken<Collection<String>>() { + }.getType(); + return StageUtils.getGson().fromJson(serializedValue, type); + } else { + return null; + } + } + + public String getCommandParameterValue(String propertyName) { + Map<String, String> commandParameters = params; + return (commandParameters == null) ? null : commandParameters.get(propertyName); + } + } + /** * A Kerberos operation type * <ul> @@ -623,7 +634,7 @@ public abstract class KerberosServerAction extends AbstractServerAction { RECREATE_ALL, /** - * Generate keytabs for only those that are missing + * Generate keytabs for only those that are missing */ CREATE_MISSING, http://git-wip-us.apache.org/repos/asf/ambari/blob/67fc4a37/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareEnableKerberosServerAction.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareEnableKerberosServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareEnableKerberosServerAction.java index 671ad95..2d29bdc 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareEnableKerberosServerAction.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareEnableKerberosServerAction.java @@ -29,11 +29,11 @@ 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.controller.KerberosHelper; +import org.apache.ambari.server.serveraction.kerberos.stageutils.ResolvedKerberosPrincipal; import org.apache.ambari.server.state.Cluster; import org.apache.ambari.server.state.ServiceComponentHost; import org.apache.ambari.server.state.kerberos.KerberosDescriptor; import org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor; -import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -70,17 +70,7 @@ public class PrepareEnableKerberosServerAction extends PrepareKerberosIdentities Map<String, String> commandParameters = getCommandParameters(); - String preconfigureServices = getCommandParameterValue(commandParameters, PRECONFIGURE_SERVICES); - PreconfigureServiceType type = null; - if (!StringUtils.isEmpty(preconfigureServices)) { - try { - type = PreconfigureServiceType.valueOf(preconfigureServices.toUpperCase()); - } catch (Throwable t) { - LOG.warn("Invalid preconfigure_services value, assuming DEFAULT: {}", preconfigureServices); - type = PreconfigureServiceType.DEFAULT; - } - } - + PreconfigureServiceType type = getCommandPreconfigureType(); KerberosDescriptor kerberosDescriptor = getKerberosDescriptor(cluster, type != PreconfigureServiceType.NONE); if (type == PreconfigureServiceType.ALL) { // Force all services to be flagged for pre-configuration... @@ -144,7 +134,7 @@ public class PrepareEnableKerberosServerAction extends PrepareKerberosIdentities } @Override - protected CommandReport processIdentity(Map<String, String> identityRecord, String evaluatedPrincipal, KerberosOperationHandler operationHandler, Map<String, String> kerberosConfiguration, Map<String, Object> requestSharedDataContext) throws AmbariException { + protected CommandReport processIdentity(ResolvedKerberosPrincipal resolvedPrincipal, KerberosOperationHandler operationHandler, Map<String, String> kerberosConfiguration, Map<String, Object> requestSharedDataContext) throws AmbariException { throw new UnsupportedOperationException(); } } http://git-wip-us.apache.org/repos/asf/ambari/blob/67fc4a37/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareKerberosIdentitiesServerAction.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareKerberosIdentitiesServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareKerberosIdentitiesServerAction.java index 83a2106..c7f2003 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareKerberosIdentitiesServerAction.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/PrepareKerberosIdentitiesServerAction.java @@ -140,15 +140,6 @@ public class PrepareKerberosIdentitiesServerAction extends AbstractPrepareKerber return createCommandReport(0, HostRoleStatus.COMPLETED, "{}", actionLog.getStdOut(), actionLog.getStdErr()); } - @Override - protected CommandReport processIdentity(Map<String, String> identityRecord, String evaluatedPrincipal, - KerberosOperationHandler operationHandler, - Map<String, String> kerberosConfiguration, - Map<String, Object> requestSharedDataContext) - throws AmbariException { - throw new UnsupportedOperationException(); - } - /** * Calls {@link KerberosHelper#getKerberosDescriptor(Cluster, boolean)} * http://git-wip-us.apache.org/repos/asf/ambari/blob/67fc4a37/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/stageutils/KerberosKeytabController.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/stageutils/KerberosKeytabController.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/stageutils/KerberosKeytabController.java new file mode 100644 index 0000000..4993902 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/stageutils/KerberosKeytabController.java @@ -0,0 +1,213 @@ +/* + * 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.stageutils; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.ambari.server.orm.dao.KerberosKeytabDAO; +import org.apache.ambari.server.orm.dao.KerberosKeytabPrincipalDAO; +import org.apache.ambari.server.orm.entities.KerberosKeytabEntity; +import org.apache.ambari.server.orm.entities.KerberosKeytabPrincipalEntity; +import org.apache.ambari.server.orm.entities.KerberosPrincipalEntity; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import com.google.inject.Inject; +import com.google.inject.Singleton; + +/** + * Helper class to construct convenient wrappers around database entities related to kerberos. + */ +@Singleton +public class KerberosKeytabController { + @Inject + private KerberosKeytabDAO kerberosKeytabDAO; + + @Inject + private KerberosKeytabPrincipalDAO kerberosKeytabPrincipalDAO; + + /** + * Tries to find keytab by keytab path in destination filesystem. + * + * @param file keytab path + * @return found keytab or null + */ + public ResolvedKerberosKeytab getKeytabByFile(String file) { + return getKeytabByFile(file, true); + } + + /** + * Tries to find keytab by keytab path in destination filesystem. + * + * @param file keytab path + * @param resolvePrincipals include resolved principals + * @return found keytab or null + */ + public ResolvedKerberosKeytab getKeytabByFile(String file, boolean resolvePrincipals) { + return fromKeytabEntity(kerberosKeytabDAO.find(file), resolvePrincipals); + } + + /** + * Returns all keytabs managed by ambari. + * + * @return all keytabs + */ + public Set<ResolvedKerberosKeytab> getAllKeytabs() { + return fromKeytabEntities(kerberosKeytabDAO.findAll()); + } + + /** + * Returns all keytabs that contains given principal. + * + * @param rkp principal to filter keytabs by + * @return set of keytabs found + */ + public Set<ResolvedKerberosKeytab> getFromPrincipal(ResolvedKerberosPrincipal rkp) { + return fromKeytabEntities(kerberosKeytabDAO.findByPrincipalAndHost(rkp.getPrincipal(), rkp.getHostId())); + } + + /** + * Returns keytabs with principals filtered by host, principal name or service(and component) names. + * + * @param serviceComponentFilter service-component filter + * @param hostFilter host filter + * @param identityFilter identity(principal) filter + * @return set of keytabs found + */ + public Set<ResolvedKerberosKeytab> getFilteredKeytabs(Map<String, Collection<String>> serviceComponentFilter, + Set<String> hostFilter, Collection<String> identityFilter) { + if (serviceComponentFilter == null && hostFilter == null && identityFilter == null) { + return getAllKeytabs(); + } + List<KerberosKeytabPrincipalDAO.KerberosKeytabPrincipalFilter> filters = splitServiceFilter(serviceComponentFilter); + for (KerberosKeytabPrincipalDAO.KerberosKeytabPrincipalFilter filter : filters) { + filter.setHostNames(hostFilter); + filter.setPrincipals(identityFilter); + } + + Set<ResolvedKerberosPrincipal> filteredPrincipals = fromPrincipalEntities(kerberosKeytabPrincipalDAO.findByFilters(filters)); + HashMap<String, ResolvedKerberosKeytab> resultMap = new HashMap<>(); + for (ResolvedKerberosPrincipal principal : filteredPrincipals) { + if (!resultMap.containsKey(principal.getKeytabPath())) { + resultMap.put(principal.getKeytabPath(), getKeytabByFile(principal.getKeytabPath(), false)); + } + ResolvedKerberosKeytab keytab = resultMap.get(principal.getKeytabPath()); + keytab.addPrincipal(principal); + } + return Sets.newHashSet(resultMap.values()); + } + + /** + * This function split serviceComponentFilter to two filters, one with specific components, and another one with service + * only. Can return only one filter if filter contain only one type of mapping(whole service or component based) + * or empty filter if no serviceComponentFilter provided. + * + * @param serviceComponentFilter + * @return + */ + private List<KerberosKeytabPrincipalDAO.KerberosKeytabPrincipalFilter> splitServiceFilter(Map<String, Collection<String>> serviceComponentFilter) { + if (serviceComponentFilter != null && serviceComponentFilter.size() > 0) { + Set<String> serviceSet = new HashSet<>(); + Set<String> componentSet = new HashSet<>(); + Set<String> serviceOnlySet = new HashSet<>(); + serviceSet.addAll(serviceComponentFilter.keySet()); + for (String serviceName : serviceSet) { + Collection<String> serviceComponents = serviceComponentFilter.get(serviceName); + if (serviceComponents.contains("*")) { // star means that this is filtered by whole SERVICE + serviceOnlySet.add(serviceName); + serviceSet.remove(serviceName); // remove service from regular + } else { + componentSet.addAll(serviceComponents); + } + } + List<KerberosKeytabPrincipalDAO.KerberosKeytabPrincipalFilter> result = new ArrayList<>(); + if (serviceSet.size() > 0) { + result.add(new KerberosKeytabPrincipalDAO.KerberosKeytabPrincipalFilter( + null, + serviceSet, + componentSet, + null + )); + } + if (serviceOnlySet.size() > 0) { + result.add(new KerberosKeytabPrincipalDAO.KerberosKeytabPrincipalFilter( + null, + serviceOnlySet, + null, + null + )); + } + if (result.size() > 0) { + return result; + } + } + + return Lists.newArrayList(new KerberosKeytabPrincipalDAO.KerberosKeytabPrincipalFilter(null,null,null,null)); + } + + private ResolvedKerberosKeytab fromKeytabEntity(KerberosKeytabEntity kke, boolean resolvePrincipals) { + Set<ResolvedKerberosPrincipal> principals = resolvePrincipals ? fromPrincipalEntities(kke.getKerberosKeytabPrincipalEntities()) : new HashSet<>(); + return new ResolvedKerberosKeytab( + kke.getKeytabPath(), + kke.getOwnerName(), + kke.getOwnerAccess(), + kke.getGroupName(), + kke.getGroupAccess(), + principals, + kke.isAmbariServerKeytab(), + kke.isWriteAmbariJaasFile() + ); + } + + private ResolvedKerberosKeytab fromKeytabEntity(KerberosKeytabEntity kke) { + return fromKeytabEntity(kke, true); + } + + private Set<ResolvedKerberosKeytab> fromKeytabEntities(Collection<KerberosKeytabEntity> keytabEntities) { + ImmutableSet.Builder<ResolvedKerberosKeytab> builder = ImmutableSet.builder(); + for (KerberosKeytabEntity kkpe : keytabEntities) { + builder.add(fromKeytabEntity(kkpe)); + } + return builder.build(); + } + + private Set<ResolvedKerberosPrincipal> fromPrincipalEntities(Collection<KerberosKeytabPrincipalEntity> principalEntities) { + ImmutableSet.Builder<ResolvedKerberosPrincipal> builder = ImmutableSet.builder(); + for (KerberosKeytabPrincipalEntity kkpe : principalEntities) { + KerberosPrincipalEntity kpe = kkpe.getPrincipalEntity(); + ResolvedKerberosPrincipal rkp = new ResolvedKerberosPrincipal( + kkpe.getHostId(), + kkpe.getHostName(), + kkpe.getPrincipalName(), + kpe.isService(), + kpe.getCachedKeytabPath(), + kkpe.getKeytabPath(), + kkpe.getServiceMappingAsMultimap()); + builder.add(rkp); + } + return builder.build(); + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/67fc4a37/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/stageutils/ResolvedKerberosKeytab.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/stageutils/ResolvedKerberosKeytab.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/stageutils/ResolvedKerberosKeytab.java index 17e484a..3233915 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/stageutils/ResolvedKerberosKeytab.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/stageutils/ResolvedKerberosKeytab.java @@ -18,21 +18,17 @@ package org.apache.ambari.server.serveraction.kerberos.stageutils; -import java.util.Map; +import java.util.HashSet; import java.util.Set; import org.apache.ambari.server.state.kerberos.VariableReplacementHelper; -import org.apache.commons.lang3.tuple.Pair; - -import com.google.common.collect.ImmutableSet; /** * Class that represents keytab. Contains principals that mapped to host. - * Same keytab can have different set of principals on different hosts. + * Same keytab can have different set of principals on different hosts for different services. + * Each principal identified by host and keytab it belongs to and contain mapping that shows in which services and + * components given principal used. */ -// TODO This class need to replace {@link org.apache.ambari.server.serveraction.kerberos.KerberosIdentityDataFile} -// TODO and all related structures and become main item that {@link org.apache.ambari.server.serveraction.kerberos.KerberosServerAction} -// TODO operates with instead of identity records. public class ResolvedKerberosKeytab { private String ownerName = null; @@ -40,43 +36,36 @@ public class ResolvedKerberosKeytab { private String groupName = null; private String groupAccess = null; private String file = null; - private Set<Pair<Long, Pair<String, String>>> mappedPrincipals = null; + private Set<ResolvedKerberosPrincipal> principals = new HashSet<>(); private boolean isAmbariServerKeytab = false; private boolean mustWriteAmbariJaasFile = false; public ResolvedKerberosKeytab( - String file, - String ownerName, - String ownerAccess, - String groupName, - String groupAccess, - Set<Pair<Long, Pair<String, String>>> mappedPrincipals, - boolean isAmbariServerKeytab, - boolean writeAmbariJaasFile + String file, + String ownerName, + String ownerAccess, + String groupName, + String groupAccess, + Set<ResolvedKerberosPrincipal> principals, + boolean isAmbariServerKeytab, + boolean writeAmbariJaasFile ) { this.ownerName = ownerName; this.ownerAccess = ownerAccess; this.groupName = groupName; this.groupAccess = groupAccess; this.file = file; - this.mappedPrincipals = mappedPrincipals; + setPrincipals(principals); this.isAmbariServerKeytab = isAmbariServerKeytab; this.mustWriteAmbariJaasFile = writeAmbariJaasFile; + } /** * Gets the path to the keytab file - * <p/> - * The value may include variable placeholders to be replaced as needed - * <ul> - * <li> - * ${variable} placeholders are replaced on the server - see - * {@link VariableReplacementHelper#replaceVariables(String, Map)} - * </li> - * </ul> * * @return a String declaring the keytab file's absolute path - * @see VariableReplacementHelper#replaceVariables(String, Map) + * @see VariableReplacementHelper#replaceVariables(String, java.util.Map) */ public String getFile() { return file; @@ -175,47 +164,36 @@ public class ResolvedKerberosKeytab { /** * Gets evaluated host-to-principal set associated with given keytab. * - * @return a Set with mappedPrincipals associated with given keytab + * @return a Set with principals associated with given keytab */ - public Set<Pair<Long, Pair<String, String>>> getMappedPrincipals() { - return mappedPrincipals; + public Set<ResolvedKerberosPrincipal> getPrincipals() { + return principals; } /** * Sets evaluated host-to-principal set associated with given keytab. * - * @param mappedPrincipals a Map with host-to-principal mapping associated with given keytab - */ - public void setMappedPrincipals(Set<Pair<Long, Pair<String, String>>> mappedPrincipals) { - this.mappedPrincipals = mappedPrincipals; - } - - /** - * Gets set of hosts associated with given keytab. - * - * @return a Set with hosts + * @param principals set of principals to add */ - public Set<Long> getHosts() { - ImmutableSet.Builder<Long> builder = ImmutableSet.builder(); - for (Pair<Long, Pair<String, String>> principal : getMappedPrincipals()) { - if (principal.getLeft() != null) { - builder.add(principal.getLeft()); + public void setPrincipals(Set<ResolvedKerberosPrincipal> principals) { + this.principals = principals; + if (principals != null) { + for (ResolvedKerberosPrincipal principal : this.principals) { + principal.setResolvedKerberosKeytab(this); } } - return builder.build(); } /** - * Gets a set of principals associated with given keytab. + * Add principal to keytab. * - * @return a Set of principals + * @param principal resolved principal to add */ - public Set<Pair<String, String>> getPrincipals() { - ImmutableSet.Builder<Pair<String, String>> builder = ImmutableSet.builder(); - for (Pair<Long, Pair<String, String>> principal : getMappedPrincipals()) { - builder.add(principal.getRight()); + public void addPrincipal(ResolvedKerberosPrincipal principal) { + if (!principals.contains(principal)) { + principal.setResolvedKerberosKeytab(this); + principals.add(principal); } - return builder.build(); } /** @@ -254,4 +232,37 @@ public class ResolvedKerberosKeytab { public void setMustWriteAmbariJaasFile(boolean mustWriteAmbariJaasFile) { this.mustWriteAmbariJaasFile = mustWriteAmbariJaasFile; } + + /** + * Merge principals from one keytab to given. + * + * @param otherKeytab keytab to merge principals from + */ + public void mergePrincipals(ResolvedKerberosKeytab otherKeytab) { + for (ResolvedKerberosPrincipal rkp : otherKeytab.getPrincipals()) { + ResolvedKerberosPrincipal existent = findPrincipal(rkp.getHostId(), rkp.getPrincipal(), rkp.getKeytabPath()); + if (existent != null) { + existent.mergeComponentMapping(rkp); + } else { + principals.add(rkp); + } + } + } + + private ResolvedKerberosPrincipal findPrincipal(Long hostId, String principal, String keytabPath) { + for (ResolvedKerberosPrincipal rkp : principals) { + boolean hostIdIsSame; + if(hostId != null && rkp.getHostId() != null){ + hostIdIsSame = hostId.equals(rkp.getHostId()); + } else if(hostId == null && rkp.getHostId() == null) { + hostIdIsSame = true; + } else { + hostIdIsSame = false; + } + if (hostIdIsSame && principal.equals(rkp.getPrincipal())&& keytabPath.equals(rkp.getKeytabPath())) { + return rkp; + } + } + return null; + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/67fc4a37/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/stageutils/ResolvedKerberosPrincipal.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/stageutils/ResolvedKerberosPrincipal.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/stageutils/ResolvedKerberosPrincipal.java new file mode 100644 index 0000000..100c1e2 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/stageutils/ResolvedKerberosPrincipal.java @@ -0,0 +1,169 @@ +/* + * 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.stageutils; + +import org.apache.ambari.server.utils.StageUtils; + +import com.google.common.base.Objects; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; + +/** + * Class that represents principal and it info(host, keytab path, service and component mapping). + */ +public class ResolvedKerberosPrincipal { + private Long hostId; + private String hostName; + private String principal; + private boolean isService; + private String cacheFile; + private Multimap<String, String> serviceMapping = ArrayListMultimap.create(); + private String keytabPath; + private ResolvedKerberosKeytab resolvedKerberosKeytab; + + public ResolvedKerberosPrincipal(Long hostId, String hostName, String principal, boolean isService, String cacheFile, String serviceName, String componentName, String keytabPath) { + this.hostId = hostId; + this.hostName = hostName; + this.principal = principal; + this.isService = isService; + this.cacheFile = cacheFile; + this.keytabPath = keytabPath; + addComponentMapping(serviceName, componentName); + } + + public ResolvedKerberosPrincipal(Long hostId, String hostName, String principal, boolean isService, String cacheFile, String keytabPath) { + this.hostId = hostId; + this.hostName = hostName; + this.principal = principal; + this.isService = isService; + this.cacheFile = cacheFile; + this.keytabPath = keytabPath; + } + + public ResolvedKerberosPrincipal(Long hostId, String hostName, String principal, boolean isService, String cacheFile, String keytabPath, Multimap<String, String> serviceMapping) { + this.hostId = hostId; + this.hostName = hostName; + this.principal = principal; + this.isService = isService; + this.cacheFile = cacheFile; + this.keytabPath = keytabPath; + this.serviceMapping = serviceMapping; + } + + public void addComponentMapping(String serviceName, String componentName) { + if (serviceName == null){ + serviceName = ""; + } + if (componentName == null) { + componentName = "*"; + } + serviceMapping.get(serviceName).add(componentName); + } + + public void mergeComponentMapping(ResolvedKerberosPrincipal other) { + serviceMapping.putAll(other.getServiceMapping()); + } + + public String getKeytabPath() { + return keytabPath; + } + + public void setKeytabPath(String keytabPath) { + this.keytabPath = keytabPath; + } + + public Long getHostId() { + return hostId; + } + + public void setHostId(Long hostId) { + this.hostId = hostId; + } + + public String getHostName() { + if (hostName == null) { + return StageUtils.getHostName(); + } + return hostName; + } + + public void setHostName(String hostName) { + this.hostName = hostName; + } + + public String getPrincipal() { + return principal; + } + + public void setPrincipal(String principal) { + this.principal = principal; + } + + public boolean isService() { + return isService; + } + + public void setService(boolean service) { + isService = service; + } + + public String getCacheFile() { + return cacheFile; + } + + public void setCacheFile(String cacheFile) { + this.cacheFile = cacheFile; + } + + public Multimap<String, String> getServiceMapping() { + return serviceMapping; + } + + public void setServiceMapping(Multimap<String, String> serviceMapping) { + this.serviceMapping = serviceMapping; + } + + public ResolvedKerberosKeytab getResolvedKerberosKeytab() { + return resolvedKerberosKeytab; + } + + public void setResolvedKerberosKeytab(ResolvedKerberosKeytab resolvedKerberosKeytab) { + this.resolvedKerberosKeytab = resolvedKerberosKeytab; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ResolvedKerberosPrincipal principal1 = (ResolvedKerberosPrincipal) o; + return isService == principal1.isService && + Objects.equal(hostId, principal1.hostId) && + Objects.equal(hostName, principal1.hostName) && + Objects.equal(principal, principal1.principal) && + Objects.equal(cacheFile, principal1.cacheFile) && + Objects.equal(serviceMapping, principal1.serviceMapping) && + Objects.equal(keytabPath, principal1.keytabPath); + } + + @Override + public int hashCode() { + return Objects.hashCode(hostId, hostName, principal, isService, cacheFile, serviceMapping, keytabPath); + } +}