AMBARI-20540. Referenced Kerberos identity definitions should be created and distributed only if the referenced service or component is installed
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/dc051199 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/dc051199 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/dc051199 Branch: refs/heads/branch-3.0-perf Commit: dc05119956a0001001d3edde443612bf42eb9ee0 Parents: d13e6fa Author: Attila Magyar <[email protected]> Authored: Fri Mar 31 19:37:50 2017 +0200 Committer: Andrew Onishuk <[email protected]> Committed: Sat Apr 1 10:07:36 2017 +0300 ---------------------------------------------------------------------- .../AbstractKerberosDescriptorContainer.java | 27 ++++++- .../kerberos/KerberosIdentityDescriptor.java | 18 +++++ .../state/kerberos/KerberosDescriptorTest.java | 19 +++++ .../test_filtering_identity_descriptor.json | 74 ++++++++++++++++++++ 4 files changed, 136 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/dc051199/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/AbstractKerberosDescriptorContainer.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/AbstractKerberosDescriptorContainer.java b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/AbstractKerberosDescriptorContainer.java index 73381ee..0a89c1d 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/AbstractKerberosDescriptorContainer.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/AbstractKerberosDescriptorContainer.java @@ -30,6 +30,13 @@ import java.util.TreeSet; import java.util.regex.Pattern; import org.apache.ambari.server.AmbariException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Function; +import com.google.common.base.Functions; +import com.google.common.base.Predicates; +import com.google.common.collect.Sets; /** * AbstractKerberosDescriptorContainer is an abstract class implementing AbstractKerberosDescriptor @@ -85,6 +92,7 @@ import org.apache.ambari.server.AmbariException; * left up to the implementing class to do so. */ public abstract class AbstractKerberosDescriptorContainer extends AbstractKerberosDescriptor { + private static final Logger LOG = LoggerFactory.getLogger(AbstractKerberosDescriptorContainer.class); /** * Regular expression pattern used to parse auth_to_local property specifications into the following @@ -244,14 +252,29 @@ public abstract class AbstractKerberosDescriptorContainer extends AbstractKerber // Make sure this Kerberos Identity is not to be filtered out based on its "when" clause if ((identityToAdd != null) && ((contextForFilter == null) || identityToAdd.shouldInclude(contextForFilter))) { - list.add(identityToAdd); + if (isReferredServiceInstalled(identity, contextForFilter)) { + list.add(identityToAdd); + } else { + LOG.info("Skipping identity {} because referred service is not installed.", identityToAdd.getName()); + } } } - return list; } } + private static boolean isReferredServiceInstalled(KerberosIdentityDescriptor identity, Map<String, Object> contextForFilter) { + if (contextForFilter == null || !(contextForFilter.get("services") instanceof Collection)) { + return true; + } + Set<String> installedServices = Sets.newHashSet((Collection) contextForFilter.get("services")); + return identity.getReferencedServiceName().transform(contains(installedServices)).or(true); + } + + private static Function<String, Boolean> contains(final Set<String> installed) { + return Functions.forPredicate(Predicates.in(installed)); + } + /** * Return a KerberosIdentityDescriptor with the specified name. * http://git-wip-us.apache.org/repos/asf/ambari/blob/dc051199/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosIdentityDescriptor.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosIdentityDescriptor.java b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosIdentityDescriptor.java index ae78de6..7c32732 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosIdentityDescriptor.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosIdentityDescriptor.java @@ -22,6 +22,8 @@ import java.util.Map; import org.apache.ambari.server.collections.Predicate; import org.apache.ambari.server.collections.PredicateUtils; +import com.google.common.base.Optional; + /** * KerberosIdentityDescriptor is an implementation of an AbstractKerberosDescriptor that * encapsulates data related to a Kerberos identity - including its principal and keytab file details. @@ -351,6 +353,22 @@ public class KerberosIdentityDescriptor extends AbstractKerberosDescriptor { return dataMap; } + /*** + * A name that refers to a service has a format like /[<service name>/[<component name>/]]<identity name> + * @return an optional referenced service name + */ + public Optional<String> getReferencedServiceName() { + return parseServiceName(reference).or(parseServiceName(getName())); + } + + private Optional<String> parseServiceName(String name) { + if (name != null && name.startsWith("/") && name.split("/").length > 2) { + return Optional.of(name.split("/")[1]); + } else { + return Optional.absent(); + } + } + @Override public int hashCode() { return super.hashCode() + http://git-wip-us.apache.org/repos/asf/ambari/blob/dc051199/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosDescriptorTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosDescriptorTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosDescriptorTest.java index f574d99..a63da61 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosDescriptorTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosDescriptorTest.java @@ -21,7 +21,9 @@ import java.io.File; import java.io.IOException; import java.net.URL; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -30,6 +32,7 @@ import java.util.TreeMap; import java.util.TreeSet; import org.apache.ambari.server.AmbariException; +import org.apache.commons.collections.map.HashedMap; import org.junit.Test; import org.junit.experimental.categories.Category; @@ -474,4 +477,20 @@ public class KerberosDescriptorTest { } Assert.assertTrue(identityFound); } + + @Test + public void testFiltersOutIdentitiesBasedonInstalledServices() throws IOException { + URL systemResourceURL = ClassLoader.getSystemResource("kerberos/test_filtering_identity_descriptor.json"); + KerberosComponentDescriptor componentDescriptor = KERBEROS_DESCRIPTOR_FACTORY.createInstance(new File(systemResourceURL.getFile())) + .getService("SERVICE1") + .getComponent("SERVICE1_COMPONENT1"); + List<KerberosIdentityDescriptor> identities = componentDescriptor.getIdentities(true, new HashedMap() {{ + put("services", Collections.emptySet()); + }}); + Assert.assertEquals(0, identities.size()); + identities = componentDescriptor.getIdentities(true, new HashedMap() {{ + put("services", Arrays.asList("REF_SERVICE1")); + }}); + Assert.assertEquals(1, identities.size()); + } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/dc051199/ambari-server/src/test/resources/kerberos/test_filtering_identity_descriptor.json ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/resources/kerberos/test_filtering_identity_descriptor.json b/ambari-server/src/test/resources/kerberos/test_filtering_identity_descriptor.json new file mode 100644 index 0000000..40f6101 --- /dev/null +++ b/ambari-server/src/test/resources/kerberos/test_filtering_identity_descriptor.json @@ -0,0 +1,74 @@ +{ + "properties": { + "realm": "${kerberos-env/realm}", + "keytab_dir": "/etc/security/keytabs" + }, + "services": [ + { + "name": "SERVICE1", + "identities": [ + { + "name": "service1_stack_reference", + "reference": "/stack_identity", + "principal": { + "configuration": "service1/property1_principal" + }, + "keytab": { + "configuration": "service1/property1_keytab", + "file": "${keytab_dir}/service1_stack.keytab" + } + } + ], + "components": [ + { + "name": "SERVICE1_COMPONENT1", + "identities": [ + { + "name": "component1_service1_stack_reference", + "reference": "/REF_SERVICE1/service1_stack_reference", + "principal": { + "configuration": "component1_service1/property1_principal" + }, + "keytab": { + "configuration": "component1_service1/property1_keytab" + } + } + ] + } + ] + }, + { + "name": "SERVICE2", + "identities": [ + { + "name": "service2_stack_reference", + "reference": "/stack_identity", + "principal": { + "configuration": "service2/property1_principal" + }, + "keytab": { + "configuration": "service2/property1_keytab", + "file": "${keytab_dir}/service2_stack.keytab" + } + } + ], + "components": [ + { + "name": "SERVICE2_COMPONENT1", + "identities": [ + { + "name": "component1_service2_stack_reference", + "reference": "/REF_SERVICE2/REF_SERVICE2_COMPONENT1/service2_stack_reference", + "principal": { + "configuration": "component1_service2/property1_principal" + }, + "keytab": { + "configuration": "component1_service2/property1_keytab" + } + } + ] + } + ] + } + ] +}
