You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by sm...@apache.org on 2018/11/16 08:55:40 UTC

[ambari] branch trunk updated: AMBARI-24907. Updated service metainfo to declare LDAP integration support (#2621)

This is an automated email from the ASF dual-hosted git repository.

smolnar pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ambari.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 9419944  AMBARI-24907. Updated service metainfo to declare LDAP integration support (#2621)
9419944 is described below

commit 9419944925f3b210ce429ba147e1462478259261
Author: Sandor Molnar <sm...@apache.org>
AuthorDate: Fri Nov 16 09:55:36 2018 +0100

    AMBARI-24907. Updated service metainfo to declare LDAP integration support (#2621)
---
 .../server/controller/AddServiceRequest.java       |   1 -
 .../ambari/server/controller/ServiceResponse.java  |  24 +++-
 .../internal/ServiceResourceProvider.java          |  14 ++
 .../apache/ambari/server/state/ServiceImpl.java    |  14 +-
 .../apache/ambari/server/state/ServiceInfo.java    |  43 ++++++
 .../ambari/server/state/ServiceLdapInfo.java       | 159 +++++++++++++++++++++
 .../ambari/server/state/ServiceInfoTest.java       |  83 +++++++++++
 7 files changed, 335 insertions(+), 3 deletions(-)

diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AddServiceRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AddServiceRequest.java
index ccf2ecf..61edde3 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AddServiceRequest.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AddServiceRequest.java
@@ -36,7 +36,6 @@ import java.util.Set;
 import org.apache.ambari.annotations.ApiIgnore;
 import org.apache.ambari.server.controller.internal.ProvisionAction;
 import org.apache.ambari.server.topology.ConfigRecommendationStrategy;
-import org.apache.ambari.server.topology.Configurable;
 import org.apache.ambari.server.topology.ConfigurableHelper;
 import org.apache.ambari.server.topology.Configuration;
 
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceResponse.java
index a0f8a56..afbf51f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceResponse.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ServiceResponse.java
@@ -41,13 +41,15 @@ public class ServiceResponse {
   private final boolean ssoIntegrationEnabled;
   private final boolean ssoIntegrationRequiresKerberos;
   private final boolean kerberosEnabled;
+  private final boolean ldapIntegrationSupported;
+  private final boolean ldapIntegrationEnabled;
 
   public ServiceResponse(Long clusterId, String clusterName, String serviceName,
                          StackId desiredStackId, String desiredRepositoryVersion,
                          RepositoryVersionState repositoryVersionState, String desiredState,
                          boolean credentialStoreSupported, boolean credentialStoreEnabled, boolean ssoIntegrationSupported,
                          boolean ssoIntegrationDesired, boolean ssoIntegrationEnabled, boolean ssoIntegrationRequiresKerberos,
-                         boolean kerberosEnabled) {
+                         boolean kerberosEnabled, boolean ldapIntegrationSupported,  boolean ldapIntegrationEnabled) {
     this.clusterId = clusterId;
     this.clusterName = clusterName;
     this.serviceName = serviceName;
@@ -62,6 +64,8 @@ public class ServiceResponse {
     this.credentialStoreEnabled = credentialStoreEnabled;
     this.ssoIntegrationRequiresKerberos = ssoIntegrationRequiresKerberos;
     this.kerberosEnabled = kerberosEnabled;
+    this.ldapIntegrationSupported = ldapIntegrationSupported;
+    this.ldapIntegrationEnabled = ldapIntegrationEnabled;
   }
 
   /**
@@ -277,6 +281,24 @@ public class ServiceResponse {
   public boolean isKerberosEnabled() {
     return kerberosEnabled;
   }
+  
+  /**
+   * Indicates if this service supports LDAP integration.
+   */
+  @ApiModelProperty(name = "ldap_integration_supported")
+  public boolean isLdapIntegrationSupported() {
+    return ldapIntegrationSupported;
+  }
+
+  /**
+   * Indicates whether the service is configured for LDAP integration or not
+   */
+  @ApiModelProperty(name = "ldap_integration_enabled")
+  public boolean isLdapIntegrationEnabled() {
+    return ldapIntegrationEnabled;
+  }
+
+
 
   /**
    * Interface to help correct Swagger documentation generation
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceResourceProvider.java
index 6b561e8..a4aaf0b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ServiceResourceProvider.java
@@ -139,6 +139,12 @@ public class ServiceResourceProvider extends AbstractControllerResourceProvider
   private static final String KERBEROS_ENABLED_PROPERTY_ID = PropertyHelper.getPropertyId(
       "ServiceInfo", "kerberos_enabled");
 
+  private static final String LDAP_INTEGRATION_SUPPORTED_PROPERTY_ID = PropertyHelper.getPropertyId(
+      "ServiceInfo", "ldap_integration_supported");
+
+  private static final String LDAP_INTEGRATION_ENABLED_PROPERTY_ID = PropertyHelper.getPropertyId(
+      "ServiceInfo", "ldap_integration_enabled");
+
   public static final String OPERATION_TYPE = "operation_type";
 
   protected static final String SERVICE_REPOSITORY_STATE = "ServiceInfo/repository_state";
@@ -185,6 +191,10 @@ public class ServiceResourceProvider extends AbstractControllerResourceProvider
     PROPERTY_IDS.add(SSO_INTEGRATION_DESIRED_PROPERTY_ID);
     PROPERTY_IDS.add(SSO_INTEGRATION_REQUIRES_KERBEROS_PROPERTY_ID);
     PROPERTY_IDS.add(KERBEROS_ENABLED_PROPERTY_ID);
+
+    PROPERTY_IDS.add(LDAP_INTEGRATION_SUPPORTED_PROPERTY_ID);
+    PROPERTY_IDS.add(LDAP_INTEGRATION_ENABLED_PROPERTY_ID);
+
     PROPERTY_IDS.add(OPERATION_TYPE);
 
     // keys
@@ -326,6 +336,10 @@ public class ServiceResourceProvider extends AbstractControllerResourceProvider
       setResourceProperty(resource, KERBEROS_ENABLED_PROPERTY_ID,
           response.isKerberosEnabled(), requestedIds);
 
+      setResourceProperty(resource, LDAP_INTEGRATION_SUPPORTED_PROPERTY_ID, response.isLdapIntegrationSupported(), requestedIds);
+      setResourceProperty(resource, LDAP_INTEGRATION_ENABLED_PROPERTY_ID, response.isLdapIntegrationEnabled(), requestedIds);
+      
+
       Map<String, Object> serviceSpecificProperties = getServiceSpecificProperties(
           response.getClusterName(), response.getServiceName(), requestedIds);
 
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java
index 23f3067..e19b43d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceImpl.java
@@ -87,6 +87,8 @@ public class ServiceImpl implements Service {
   private boolean isCredentialStoreRequired;
   private final boolean ssoIntegrationSupported;
   private final Predicate ssoEnabledTest;
+  private final boolean ldapIntegrationSupported;
+  private final Predicate ldapEnabledTest;
   private final boolean ssoRequiresKerberos;
   private final Predicate kerberosEnabledTest;
   private AmbariMetaInfo ambariMetaInfo;
@@ -169,6 +171,9 @@ public class ServiceImpl implements Service {
           serviceName);
     }
 
+    ldapIntegrationSupported = sInfo.isLdapSupported();
+    ldapEnabledTest = StringUtils.isNotBlank(sInfo.getLdapEnabledTest()) ? PredicateUtils.fromJSON(sInfo.getLdapEnabledTest()) : null;
+
     persist(serviceEntity);
   }
 
@@ -226,6 +231,9 @@ public class ServiceImpl implements Service {
               "Automated SSO integration will not be allowed for this service.",
           serviceName);
     }
+
+    ldapIntegrationSupported = sInfo.isLdapSupported();
+    ldapEnabledTest = StringUtils.isNotBlank(sInfo.getLdapEnabledTest()) ? PredicateUtils.fromJSON(sInfo.getLdapEnabledTest()) : null;
   }
 
 
@@ -414,7 +422,7 @@ public class ServiceImpl implements Service {
         getName(), desiredStackId, desiredRespositoryVersion.getVersion(), getRepositoryState(),
         getDesiredState().toString(), isCredentialStoreSupported(), isCredentialStoreEnabled(),
         ssoIntegrationSupported, isSsoIntegrationDesired(), isSsoIntegrationEnabled(existingConfigurations),
-        isKerberosRequiredForSsoIntegration(), isKerberosEnabled(existingConfigurations));
+        isKerberosRequiredForSsoIntegration(), isKerberosEnabled(existingConfigurations), ldapIntegrationSupported,isLdapIntegrationEnabeled(existingConfigurations));
 
     r.setDesiredRepositoryVersionId(desiredRespositoryVersion.getId());
 
@@ -797,4 +805,8 @@ public class ServiceImpl implements Service {
   private boolean isKerberosRequiredForSsoIntegration() {
     return ssoRequiresKerberos;
   }
+
+  private boolean isLdapIntegrationEnabeled(Map<String, Map<String, String>> existingConfigurations) {
+    return ldapIntegrationSupported && ldapEnabledTest != null && ldapEnabledTest.evaluate(existingConfigurations);
+  }
 }
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java
index a4ce569..fa17dea 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceInfo.java
@@ -167,6 +167,12 @@ public class ServiceInfo implements Validable {
   @XmlElements(@XmlElement(name = "sso"))
   private SingleSignOnInfo singleSignOnInfo;
 
+  /**
+   * LDAP support information
+   */
+  @XmlElements(@XmlElement(name = "ldap"))
+  private ServiceLdapInfo ldapInfo;
+
   public Boolean isRestartRequiredAfterChange() {
     return restartRequiredAfterChange;
   }
@@ -719,6 +725,38 @@ public class ServiceInfo implements Validable {
   public boolean isKerberosRequiredForSingleSignOnIntegration() {
     return singleSignOnInfo != null && singleSignOnInfo.isKerberosRequired();
   }
+  
+  /**
+   * Gets a new value for LDAP integration support
+   */
+  public ServiceLdapInfo getLdapInfo() {
+    return ldapInfo;
+  }
+
+  /**
+   * Sets a new value for LDAP integration support
+   * 
+   * @param ldapInfo
+   *          a {@link ServiceLdapInfo}
+   */
+  public void setLdapInfo(ServiceLdapInfo ldapInfo) {
+    this.ldapInfo = ldapInfo;
+  }
+
+  /**
+   * @return whether this service supports single sign-on integration
+   */
+  public boolean isLdapSupported() {
+    return (ldapInfo != null) && ldapInfo.isSupported();
+  }
+
+  /**
+   * @return the configuration specification that can be used to determine if LDAP
+   *         has been enabled or not.
+   */
+  public String getLdapEnabledTest() {
+    return ldapInfo != null ? ldapInfo.getLdapEnabledTest() : null;
+  }
 
   @Override
   public String toString() {
@@ -1332,6 +1370,11 @@ public class ServiceInfo implements Validable {
         }
       }
     }
+
+    if (ldapInfo != null && ldapInfo.isSupported() && StringUtils.isBlank(ldapInfo.getLdapEnabledTest())) {
+      setValid(false);
+      addError("LDAP support is indicated for service " + getName() + " but no test configuration has been set by ldapEnabledTest."); 
+    }
   }
 
   public enum Selection {
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceLdapInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceLdapInfo.java
new file mode 100644
index 0000000..709b607
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceLdapInfo.java
@@ -0,0 +1,159 @@
+/*
+ * 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.state;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+
+import org.apache.ambari.server.collections.PredicateUtils;
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.commons.lang.builder.HashCodeBuilder;
+import org.apache.commons.lang.builder.ToStringBuilder;
+
+/**
+ * {@link ServiceLdapInfo} encapsulates meta information about a service's
+ * support LDAP integration
+ * <p>
+ * The data is expected to be like
+ * 
+ * <pre>
+ *   &lt;ldap&gt;
+ *     &lt;supported&gt;true&lt;/supported&gt;
+ *     &lt;ldapEnabledTest&gt;
+ *         {
+ *           "equals": [
+ *             "service-site/ranger.authentication.method",
+ *             "LDAP"
+ *           ]
+ *         }
+ *     &lt;/ldapEnabledTest&gt;
+ *   &lt;/ldap&gt;
+ * </pre>
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+public class ServiceLdapInfo {
+
+  /**
+   * Indicates whether the relevant service supports LDAP integration
+   * (<code>true</code>) or not (<code>false</code>).
+   */
+  @XmlElement(name = "supported")
+  private Boolean supported = Boolean.FALSE;
+
+  /**
+   * The configuration that can be used to determine if LDAP integration has been
+   * enabled.
+   * <p>
+   * It is expected that this value is in the form of a valid JSON predicate
+   * ({@link PredicateUtils#fromJSON(String)}
+   */
+  @XmlElement(name = "ldapEnabledTest")
+  private String ldapEnabledTest = null;
+
+  /**
+   * Default constructor
+   */
+  public ServiceLdapInfo() {
+    this(Boolean.FALSE, null);
+  }
+
+  /**
+   * Constructor taking in values for supported and the configuration that can be
+   * used to determine if it is enabled for not.
+   *
+   * @param supported
+   *          true if LDAP integration is supported; false otherwise
+   * @param ldapEnabledTest
+   *          the configuration that can be used to determine if LDAP integration
+   *          has been enabled
+   */
+  public ServiceLdapInfo(Boolean supported, String ldapEnabledTest) {
+    this.supported = supported;
+    this.ldapEnabledTest = ldapEnabledTest;
+  }
+
+  /**
+   * Gets the value whether if the service supports LDAP integration.
+   * <p>
+   * <code>null</code> indicates the value was not set
+   *
+   * @return true if LDAP integration is supported; false if LDAP integration is
+   *         not supported; null if not specified
+   */
+  public Boolean getSupported() {
+    return supported;
+  }
+
+  /**
+   * Tests whether the service supports LDAP integration.
+   *
+   * @return true if LDAP integration is supported; false otherwise
+   */
+  public boolean isSupported() {
+    return Boolean.TRUE.equals(supported);
+  }
+
+  /**
+   * Sets the value indicating whether the service supports LDAP integration.
+   *
+   * @param supported
+   *          true if LDAP integration is supported; false if LDAP integration is
+   *          not supported; null if not specified
+   */
+  public void setSupported(Boolean supported) {
+    this.supported = supported;
+  }
+
+  /**
+   * Gets the configuration specification that can be used to determine if LDAP
+   * has been enabled or not.
+   *
+   * @return a configuration specification (a valid JSON predicate)
+   */
+  public String getLdapEnabledTest() {
+    return ldapEnabledTest;
+  }
+
+  /**
+   * Sets the configuration specification that can be used to determine if LDAP
+   * has been enabled or not.
+   *
+   * @param ldapEnabledTest
+   *          a configuration specification (a valid JSON predicate)
+   */
+  public void setLdapEnabledTest(String ldapEnabledTest) {
+    this.ldapEnabledTest = ldapEnabledTest;
+  }
+
+  @Override
+  public int hashCode() {
+    return HashCodeBuilder.reflectionHashCode(this);
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    return EqualsBuilder.reflectionEquals(this, obj);
+  }
+
+  @Override
+  public String toString() {
+    return ToStringBuilder.reflectionToString(this);
+  }
+}
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/ServiceInfoTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/ServiceInfoTest.java
index 00223c4..df7bc6f 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/ServiceInfoTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/ServiceInfoTest.java
@@ -847,6 +847,89 @@ public class ServiceInfoTest {
     service = serviceInfoMap.get("HDFS");
     assertNull(service.getKerberosEnabledTest());
   }
+  
+  @Test
+  public void testLdapIntegrationSupport() throws Exception {
+    // Implicit SSO setting
+    String serviceInfoXml =
+        "<metainfo>" +
+            "  <schemaVersion>2.0</schemaVersion>" +
+            "  <services>" +
+            "    <service>" +
+            "      <name>SERVICE</name>" +
+            "    </service>" +
+            "  </services>" +
+            "</metainfo>";
+    Map<String, ServiceInfo> serviceInfoMap = getServiceInfo(serviceInfoXml);
+    assertFalse(serviceInfoMap.get("SERVICE").isLdapSupported());
+    assertTrue(serviceInfoMap.get("SERVICE").isValid());
+
+    ServiceLdapInfo ldapInfo = serviceInfoMap.get("SERVICE").getLdapInfo();
+    assertNull(ldapInfo);
+
+    // Explicit LDAP setting (true)
+    serviceInfoXml =
+        "<metainfo>" +
+            "  <schemaVersion>2.0</schemaVersion>" +
+            "  <services>" +
+            "    <service>" +
+            "      <name>SERVICE</name>" +
+            "      <ldap>" +
+            "        <supported>true</supported>" +
+            "        <ldapEnabledTest>{\"equals\": [\"config-type/property_name\", \"true\"]}</ldapEnabledTest>" +
+            "      </ldap>" +
+            "    </service>" +
+            "  </services>" +
+            "</metainfo>";
+    serviceInfoMap = getServiceInfo(serviceInfoXml);
+    assertTrue(serviceInfoMap.get("SERVICE").isLdapSupported());
+    assertTrue(serviceInfoMap.get("SERVICE").isValid());
+
+    ldapInfo = serviceInfoMap.get("SERVICE").getLdapInfo();
+    assertNotNull(ldapInfo);
+    assertTrue(ldapInfo.isSupported());
+    assertEquals("{\"equals\": [\"config-type/property_name\", \"true\"]}", ldapInfo.getLdapEnabledTest());
+
+    // Explicit LDAP setting (false)
+    serviceInfoXml =
+        "<metainfo>" +
+            "  <schemaVersion>2.0</schemaVersion>" +
+            "  <services>" +
+            "    <service>" +
+            "      <name>SERVICE</name>" +
+            "      <ldap>" +
+            "        <supported>false</supported>" +
+            "      </ldap>" +
+            "    </service>" +
+            "  </services>" +
+            "</metainfo>";
+    serviceInfoMap = getServiceInfo(serviceInfoXml);
+    assertFalse(serviceInfoMap.get("SERVICE").isLdapSupported());
+    assertTrue(serviceInfoMap.get("SERVICE").isValid());
+
+    ldapInfo = serviceInfoMap.get("SERVICE").getLdapInfo();
+    assertNotNull(ldapInfo);
+    assertFalse(ldapInfo.isSupported());
+    assertNull(ldapInfo.getLdapEnabledTest());
+
+    // Explicit SSO setting (invalid)
+    serviceInfoXml =
+        "<metainfo>" +
+            "  <schemaVersion>2.0</schemaVersion>" +
+            "  <services>" +
+            "    <service>" +
+            "      <name>SERVICE</name>" +
+            "      <ldap>" +
+            "        <supported>true</supported>" +
+            "      </ldap>" +
+            "    </service>" +
+            "  </services>" +
+            "</metainfo>";
+    serviceInfoMap = getServiceInfo(serviceInfoXml);
+    assertTrue(serviceInfoMap.get("SERVICE").isLdapSupported());
+    assertFalse(serviceInfoMap.get("SERVICE").isValid());
+    assertEquals(1, serviceInfoMap.get("SERVICE").getErrors().size());
+  }
 
   @Test
   public void testIsRollingRestartSupported() throws JAXBException {