You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by rl...@apache.org on 2018/07/30 22:23:37 UTC

[ambari] branch branch-2.7 updated: [AMBARI-24384] Logic and declaration used to determine if Kerberos is enabled for a service

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

rlevas pushed a commit to branch branch-2.7
in repository https://gitbox.apache.org/repos/asf/ambari.git


The following commit(s) were added to refs/heads/branch-2.7 by this push:
     new 1372f03  [AMBARI-24384] Logic and declaration used to determine if Kerberos is enabled for a service
1372f03 is described below

commit 1372f03a0b19457467002c8eea5f900b9fbb1e86
Author: Robert Levas <rl...@hortonworks.com>
AuthorDate: Mon Jul 30 16:43:56 2018 -0400

    [AMBARI-24384] Logic and declaration used to determine if Kerberos is enabled for a service
---
 .../ambari/server/controller/ServiceResponse.java  |  21 ++-
 .../internal/ServiceResourceProvider.java          |   6 +
 .../org/apache/ambari/server/state/Service.java    |  19 +++
 .../apache/ambari/server/state/ServiceImpl.java    | 178 +++++++++++++--------
 .../apache/ambari/server/state/ServiceInfo.java    |  32 ++++
 .../ambari/server/state/ServiceInfoTest.java       |  57 +++++++
 .../apache/ambari/server/state/ServiceTest.java    |  56 +++++++
 .../stacks/HDP/0.1/services/HDFS/metainfo.xml      |  19 +++
 8 files changed, 319 insertions(+), 69 deletions(-)

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 7502f50..a0f8a56 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
@@ -40,12 +40,14 @@ public class ServiceResponse {
   private final boolean ssoIntegrationDesired;
   private final boolean ssoIntegrationEnabled;
   private final boolean ssoIntegrationRequiresKerberos;
+  private final boolean kerberosEnabled;
 
   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 ssoIntegrationDesired, boolean ssoIntegrationEnabled, boolean ssoIntegrationRequiresKerberos,
+                         boolean kerberosEnabled) {
     this.clusterId = clusterId;
     this.clusterName = clusterName;
     this.serviceName = serviceName;
@@ -59,10 +61,9 @@ public class ServiceResponse {
     this.credentialStoreSupported = credentialStoreSupported;
     this.credentialStoreEnabled = credentialStoreEnabled;
     this.ssoIntegrationRequiresKerberos = ssoIntegrationRequiresKerberos;
+    this.kerberosEnabled = kerberosEnabled;
   }
 
-
-
   /**
    * @return the serviceName
    */
@@ -231,7 +232,7 @@ public class ServiceResponse {
 
   @Override
   public int hashCode() {
-    int result = clusterId != null? clusterId.intValue() : 0;
+    int result = clusterId != null ? clusterId.intValue() : 0;
     result = 71 * result + (clusterName != null ? clusterName.hashCode() : 0);
     result = 71 * result + (serviceName != null ? serviceName.hashCode() : 0);
     return result;
@@ -270,6 +271,14 @@ public class ServiceResponse {
   }
 
   /**
+   * Indicates whether the service is configured for Kerberos or not
+   */
+  @ApiModelProperty(name = "kerberos_enabled")
+  public boolean isKerberosEnabled() {
+    return kerberosEnabled;
+  }
+
+  /**
    * Interface to help correct Swagger documentation generation
    */
   public interface ServiceResponseSwagger extends ApiModel {
@@ -278,14 +287,14 @@ public class ServiceResponse {
   }
 
   /**
-   * @param id
+   * @param id the desired repository id
    */
   public void setDesiredRepositoryVersionId(Long id) {
     desiredRepositoryVersionId = id;
   }
 
   /**
-   * @param id
+   * @return the desired repository id
    */
   public Long getDesiredRepositoryVersionId() {
     return desiredRepositoryVersionId;
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 cb9ef00..7302833 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
@@ -133,6 +133,9 @@ public class ServiceResourceProvider extends AbstractControllerResourceProvider
   private static final String SSO_INTEGRATION_REQUIRES_KERBEROS_PROPERTY_ID = PropertyHelper.getPropertyId(
       "ServiceInfo", "sso_integration_requires_kerberos");
 
+  private static final String KERBEROS_ENABLED_PROPERTY_ID = PropertyHelper.getPropertyId(
+      "ServiceInfo", "kerberos_enabled");
+
   protected static final String SERVICE_REPOSITORY_STATE = "ServiceInfo/repository_state";
 
   //Parameters from the predicate
@@ -176,6 +179,7 @@ public class ServiceResourceProvider extends AbstractControllerResourceProvider
     PROPERTY_IDS.add(SSO_INTEGRATION_ENABLED_PROPERTY_ID);
     PROPERTY_IDS.add(SSO_INTEGRATION_DESIRED_PROPERTY_ID);
     PROPERTY_IDS.add(SSO_INTEGRATION_REQUIRES_KERBEROS_PROPERTY_ID);
+    PROPERTY_IDS.add(KERBEROS_ENABLED_PROPERTY_ID);
 
     // keys
     KEY_PROPERTY_IDS.put(Resource.Type.Service, SERVICE_SERVICE_NAME_PROPERTY_ID);
@@ -301,6 +305,8 @@ public class ServiceResourceProvider extends AbstractControllerResourceProvider
         response.isSsoIntegrationDesired(), requestedIds);
       setResourceProperty(resource, SSO_INTEGRATION_REQUIRES_KERBEROS_PROPERTY_ID,
         response.isSsoIntegrationRequiresKerberos(), requestedIds);
+      setResourceProperty(resource, KERBEROS_ENABLED_PROPERTY_ID,
+          response.isKerberosEnabled(), requestedIds);
 
       Map<String, Object> serviceSpecificProperties = getServiceSpecificProperties(
           response.getClusterName(), response.getServiceName(), requestedIds);
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/Service.java b/ambari-server/src/main/java/org/apache/ambari/server/state/Service.java
index b6203f9..186c9ec 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/Service.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/Service.java
@@ -90,6 +90,25 @@ public interface Service {
   MaintenanceState getMaintenanceState();
 
   /**
+   * Tests to see if Kerberos is enabled for this service using the Kerberos enabled test metadata
+   * and the existing cluster configurations.
+   *
+   * @return <code>true</code>. if it is determined that Kerberos is enabled for this service; <code>false</code>, otherwise
+   * @see #isKerberosEnabled(Map)
+   */
+  boolean isKerberosEnabled();
+
+  /**
+   * Tests to see if Kerberos is enabled for this service using the Kerberos enabled test metadata
+   * and the supplied configurations map.
+   *
+   * @param configurations a map of configurations to use for the test
+   * @return <code>true</code>. if it is determined that Kerberos is enabled for this service; <code>false</code>, otherwise
+   * @see #isKerberosEnabled()
+   */
+  boolean isKerberosEnabled(Map<String, Map<String, String>> configurations);
+
+  /**
    * Refresh Service info due to current stack
    * @throws AmbariException
    */
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 52d4a23..23f3067 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
@@ -20,6 +20,7 @@ package org.apache.ambari.server.state;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -32,7 +33,6 @@ import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
 
 import org.apache.ambari.server.AmbariException;
-import org.apache.ambari.server.AmbariRuntimeException;
 import org.apache.ambari.server.ObjectNotFoundException;
 import org.apache.ambari.server.ServiceComponentNotFoundException;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
@@ -86,8 +86,9 @@ public class ServiceImpl implements Service {
   private boolean isCredentialStoreSupported;
   private boolean isCredentialStoreRequired;
   private final boolean ssoIntegrationSupported;
-  private final Predicate ssoEnabledConfiguration;
+  private final Predicate ssoEnabledTest;
   private final boolean ssoRequiresKerberos;
+  private final Predicate kerberosEnabledTest;
   private AmbariMetaInfo ambariMetaInfo;
   private AtomicReference<MaintenanceState> maintenanceState = new AtomicReference<>();
 
@@ -121,10 +122,10 @@ public class ServiceImpl implements Service {
 
   @AssistedInject
   ServiceImpl(@Assisted Cluster cluster, @Assisted String serviceName,
-      @Assisted RepositoryVersionEntity desiredRepositoryVersion, ClusterDAO clusterDAO,
-      ClusterServiceDAO clusterServiceDAO, ServiceDesiredStateDAO serviceDesiredStateDAO,
-      ServiceComponentFactory serviceComponentFactory, AmbariMetaInfo ambariMetaInfo,
-      AmbariEventPublisher eventPublisher) throws AmbariException {
+              @Assisted RepositoryVersionEntity desiredRepositoryVersion, ClusterDAO clusterDAO,
+              ClusterServiceDAO clusterServiceDAO, ServiceDesiredStateDAO serviceDesiredStateDAO,
+              ServiceComponentFactory serviceComponentFactory, AmbariMetaInfo ambariMetaInfo,
+              AmbariEventPublisher eventPublisher) throws AmbariException {
     this.cluster = cluster;
     this.clusterDAO = clusterDAO;
     this.clusterServiceDAO = clusterServiceDAO;
@@ -157,32 +158,26 @@ public class ServiceImpl implements Service {
     isCredentialStoreSupported = sInfo.isCredentialStoreSupported();
     isCredentialStoreRequired = sInfo.isCredentialStoreRequired();
     ssoIntegrationSupported = sInfo.isSingleSignOnSupported();
-    ssoEnabledConfiguration = compileSsoEnabledPredicate(sInfo);
+    ssoEnabledTest = compileSsoEnabledPredicate(sInfo);
     ssoRequiresKerberos = sInfo.isKerberosRequiredForSingleSignOnIntegration();
+    kerberosEnabledTest = compileKerberosEnabledPredicate(sInfo);
 
-    persist(serviceEntity);
-  }
-
-  private Predicate compileSsoEnabledPredicate(ServiceInfo sInfo) {
-    if (StringUtils.isNotBlank(sInfo.getSingleSignOnEnabledTest())) {
-      if (StringUtils.isNotBlank(sInfo.getSingleSignOnEnabledConfiguration())) {
-        LOG.warn("Both <ssoEnabledTest> and <enabledConfiguration> have been declared within <sso> for {}; using <ssoEnabledTest>", serviceName);
-      }
-      return PredicateUtils.fromJSON(sInfo.getSingleSignOnEnabledTest());
-    } else if (StringUtils.isNotBlank(sInfo.getSingleSignOnEnabledConfiguration())) {
-      LOG.warn("Only <enabledConfiguration> have been declared  within <sso> for {}; converting its value to an equals predicate", serviceName);
-      final String equalsPredicateJson = "{\"equals\": [\"" + sInfo.getSingleSignOnEnabledConfiguration() + "\", \"true\"]}";
-      return PredicateUtils.fromJSON(equalsPredicateJson);
+    if (ssoIntegrationSupported && ssoRequiresKerberos && (kerberosEnabledTest == null)) {
+      LOG.warn("The service, {}, requires Kerberos to be enabled for SSO integration support; " +
+              "however, the kerberosEnabledTest specification has not been specified in the metainfo.xml file. " +
+              "Automated SSO integration will not be allowed for this service.",
+          serviceName);
     }
-    return null;
+
+    persist(serviceEntity);
   }
 
   @AssistedInject
   ServiceImpl(@Assisted Cluster cluster, @Assisted ClusterServiceEntity serviceEntity,
-      ClusterDAO clusterDAO, ClusterServiceDAO clusterServiceDAO,
-      ServiceDesiredStateDAO serviceDesiredStateDAO,
-      ServiceComponentFactory serviceComponentFactory, AmbariMetaInfo ambariMetaInfo,
-      AmbariEventPublisher eventPublisher) throws AmbariException {
+              ClusterDAO clusterDAO, ClusterServiceDAO clusterServiceDAO,
+              ServiceDesiredStateDAO serviceDesiredStateDAO,
+              ServiceComponentFactory serviceComponentFactory, AmbariMetaInfo ambariMetaInfo,
+              AmbariEventPublisher eventPublisher) throws AmbariException {
     this.cluster = cluster;
     this.clusterDAO = clusterDAO;
     this.clusterServiceDAO = clusterServiceDAO;
@@ -200,16 +195,16 @@ public class ServiceImpl implements Service {
       for (ServiceComponentDesiredStateEntity serviceComponentDesiredStateEntity
           : serviceEntity.getServiceComponentDesiredStateEntities()) {
         try {
-            components.put(serviceComponentDesiredStateEntity.getComponentName(),
-                serviceComponentFactory.createExisting(this,
-                    serviceComponentDesiredStateEntity));
-          } catch(ProvisionException ex) {
-            StackId stackId = new StackId(serviceComponentDesiredStateEntity.getDesiredStack());
-            LOG.error(String.format("Can not get component info: stackName=%s, stackVersion=%s, serviceName=%s, componentName=%s",
-                stackId.getStackName(), stackId.getStackVersion(),
-                serviceEntity.getServiceName(),serviceComponentDesiredStateEntity.getComponentName()));
-            ex.printStackTrace();
-          }
+          components.put(serviceComponentDesiredStateEntity.getComponentName(),
+              serviceComponentFactory.createExisting(this,
+                  serviceComponentDesiredStateEntity));
+        } catch (ProvisionException ex) {
+          StackId stackId = new StackId(serviceComponentDesiredStateEntity.getDesiredStack());
+          LOG.error(String.format("Can not get component info: stackName=%s, stackVersion=%s, serviceName=%s, componentName=%s",
+              stackId.getStackName(), stackId.getStackVersion(),
+              serviceEntity.getServiceName(), serviceComponentDesiredStateEntity.getComponentName()));
+          ex.printStackTrace();
+        }
       }
     }
 
@@ -221,8 +216,16 @@ public class ServiceImpl implements Service {
     isCredentialStoreRequired = sInfo.isCredentialStoreRequired();
     displayName = sInfo.getDisplayName();
     ssoIntegrationSupported = sInfo.isSingleSignOnSupported();
-    ssoEnabledConfiguration = compileSsoEnabledPredicate(sInfo);
+    ssoEnabledTest = compileSsoEnabledPredicate(sInfo);
     ssoRequiresKerberos = sInfo.isKerberosRequiredForSingleSignOnIntegration();
+    kerberosEnabledTest = compileKerberosEnabledPredicate(sInfo);
+
+    if (ssoIntegrationSupported && ssoRequiresKerberos && (kerberosEnabledTest == null)) {
+      LOG.warn("The service, {}, requires Kerberos to be enabled for SSO integration support; " +
+              "however, the kerberosEnabledTest specification has not been specified in the metainfo.xml file. " +
+              "Automated SSO integration will not be allowed for this service.",
+          serviceName);
+    }
   }
 
 
@@ -241,10 +244,10 @@ public class ServiceImpl implements Service {
 
     } catch (ObjectNotFoundException e) {
       throw new RuntimeException("Trying to create a ServiceInfo"
-              + " not recognized in stack info"
-              + ", clusterName=" + cluster.getClusterName()
-              + ", serviceName=" + getName()
-              + ", stackInfo=" + getDesiredStackId().getStackName());
+          + " not recognized in stack info"
+          + ", clusterName=" + cluster.getClusterName()
+          + ", serviceName=" + getName()
+          + ", stackInfo=" + getDesiredStackId().getStackName());
     }
   }
 
@@ -271,7 +274,7 @@ public class ServiceImpl implements Service {
   @Override
   public Set<String> getServiceHosts() {
     Set<String> hostNames = new HashSet<>();
-    for (ServiceComponent serviceComponent  : getServiceComponents().values()) {
+    for (ServiceComponent serviceComponent : getServiceComponents().values()) {
       hostNames.addAll(serviceComponent.getServiceComponentsHosts());
     }
     return hostNames;
@@ -328,7 +331,7 @@ public class ServiceImpl implements Service {
   public void setDesiredState(State state) {
     if (LOG.isDebugEnabled()) {
       LOG.debug("Setting DesiredState of Service, clusterName={}, clusterId={}, serviceName={}, oldDesiredState={}, newDesiredState={}",
-        cluster.getClusterName(), cluster.getClusterId(), getName(), getDesiredState(), state);
+          cluster.getClusterName(), cluster.getClusterId(), getName(), getDesiredState(), state);
     }
 
     ServiceDesiredStateEntity serviceDesiredStateEntity = getServiceDesiredStateEntity();
@@ -386,7 +389,7 @@ public class ServiceImpl implements Service {
     }
 
     List<RepositoryVersionState> states = new ArrayList<>();
-    for( ServiceComponent component : components.values() ){
+    for (ServiceComponent component : components.values()) {
       states.add(component.getRepositoryState());
     }
 
@@ -398,10 +401,20 @@ public class ServiceImpl implements Service {
     RepositoryVersionEntity desiredRespositoryVersion = getDesiredRepositoryVersion();
     StackId desiredStackId = desiredRespositoryVersion.getStackId();
 
+    Map<String, Map<String, String>> existingConfigurations;
+
+    try {
+      existingConfigurations = configHelper.calculateExistingConfigurations(ambariManagementController, cluster);
+    } catch (AmbariException e) {
+      LOG.warn("Failed to get the existing configurations for the cluster.  Predicate calculations may not be correct due to missing data.");
+      existingConfigurations = Collections.emptyMap();
+    }
+
     ServiceResponse r = new ServiceResponse(cluster.getClusterId(), cluster.getClusterName(),
         getName(), desiredStackId, desiredRespositoryVersion.getVersion(), getRepositoryState(),
         getDesiredState().toString(), isCredentialStoreSupported(), isCredentialStoreEnabled(),
-      ssoIntegrationSupported, isSsoIntegrationDesired(), isSsoIntegrationEnabled(), isKerberosRequredForSsoIntegration());
+        ssoIntegrationSupported, isSsoIntegrationDesired(), isSsoIntegrationEnabled(existingConfigurations),
+        isKerberosRequiredForSsoIntegration(), isKerberosEnabled(existingConfigurations));
 
     r.setDesiredRepositoryVersionId(desiredRespositoryVersion.getId());
 
@@ -451,7 +464,7 @@ public class ServiceImpl implements Service {
       return desiredStateEntity.isCredentialStoreEnabled();
     } else {
       LOG.warn("Trying to fetch a member from an entity object that may " +
-              "have been previously deleted, serviceName = " + getName());
+          "have been previously deleted, serviceName = " + getName());
     }
     return false;
   }
@@ -467,7 +480,7 @@ public class ServiceImpl implements Service {
   public void setCredentialStoreEnabled(boolean credentialStoreEnabled) {
     if (LOG.isDebugEnabled()) {
       LOG.debug("Setting CredentialStoreEnabled of Service, clusterName={}, clusterId={}, serviceName={}, oldCredentialStoreEnabled={}, newCredentialStoreEnabled={}",
-        cluster.getClusterName(), cluster.getClusterId(), getName(), isCredentialStoreEnabled(), credentialStoreEnabled);
+          cluster.getClusterName(), cluster.getClusterId(), getName(), isCredentialStoreEnabled(), credentialStoreEnabled);
     }
 
     ServiceDesiredStateEntity desiredStateEntity = getServiceDesiredStateEntity();
@@ -479,7 +492,7 @@ public class ServiceImpl implements Service {
         StackId stackId = getDesiredStackId();
         serviceCredentialStoreUpdateEvent =
             new ServiceCredentialStoreUpdateEvent(getClusterId(), stackId.getStackName(),
-                                                  stackId.getStackVersion(), getName());
+                stackId.getStackVersion(), getName());
       }
       desiredStateEntity.setCredentialStoreEnabled(credentialStoreEnabled);
       desiredStateEntity = serviceDesiredStateDAO.merge(desiredStateEntity);
@@ -490,18 +503,18 @@ public class ServiceImpl implements Service {
       }
     } else {
       LOG.warn("Setting a member on an entity object that may have been "
-              + "previously deleted, serviceName = " + getName());
+          + "previously deleted, serviceName = " + getName());
     }
   }
 
   @Override
   public void debugDump(StringBuilder sb) {
     sb.append("Service={ serviceName=").append(getName())
-      .append(", clusterName=").append(cluster.getClusterName())
-      .append(", clusterId=").append(cluster.getClusterId())
-      .append(", desiredStackVersion=").append(getDesiredStackId())
-      .append(", desiredState=").append(getDesiredState())
-      .append(", components=[ ");
+        .append(", clusterName=").append(cluster.getClusterName())
+        .append(", clusterId=").append(cluster.getClusterId())
+        .append(", desiredStackVersion=").append(getDesiredStackId())
+        .append(", desiredState=").append(getDesiredState())
+        .append(", components=[ ");
     boolean first = true;
     for (ServiceComponent sc : components.values()) {
       if (!first) {
@@ -578,7 +591,7 @@ public class ServiceImpl implements Service {
     LOG.info("Deleting all configuration associations for {} on cluster {}", getName(), cluster.getClusterName());
 
     List<ServiceConfigEntity> serviceConfigEntities =
-      serviceConfigDAO.findByService(cluster.getClusterId(), getName());
+        serviceConfigDAO.findByService(cluster.getClusterId(), getName());
 
     for (ServiceConfigEntity serviceConfigEntity : serviceConfigEntities) {
       // Only delete the historical version information and not original
@@ -710,6 +723,29 @@ public class ServiceImpl implements Service {
     return maintenanceState.get();
   }
 
+  @Override
+  public boolean isKerberosEnabled() {
+    if (kerberosEnabledTest != null) {
+      Map<String, Map<String, String>> existingConfigurations;
+
+      try {
+        existingConfigurations = configHelper.calculateExistingConfigurations(ambariManagementController, cluster);
+      } catch (AmbariException e) {
+        LOG.warn("Failed to get the existing configurations for the cluster.  Predicate calculations may not be correct due to missing data.");
+        existingConfigurations = Collections.emptyMap();
+      }
+      return isKerberosEnabled(existingConfigurations);
+    }
+
+    return false;
+  }
+
+  @Override
+  public boolean isKerberosEnabled(Map<String, Map<String, String>> configurations) {
+    return kerberosEnabledTest != null && kerberosEnabledTest.evaluate(configurations);
+  }
+
+
   private ClusterServiceEntityPK getServiceEntityPK(ClusterServiceEntity serviceEntity) {
     ClusterServiceEntityPK pk = new ClusterServiceEntityPK();
     pk.setClusterId(serviceEntity.getClusterId());
@@ -729,20 +765,36 @@ public class ServiceImpl implements Service {
     return serviceDesiredStateDAO.findByPK(serviceDesiredStateEntityPK);
   }
 
-  public boolean isSsoIntegrationDesired() {
-    return ambariServerConfigurationHandler.getSSOEnabledServices().contains(serviceName);
+  private Predicate compileSsoEnabledPredicate(ServiceInfo sInfo) {
+    if (StringUtils.isNotBlank(sInfo.getSingleSignOnEnabledTest())) {
+      if (StringUtils.isNotBlank(sInfo.getSingleSignOnEnabledConfiguration())) {
+        LOG.warn("Both <ssoEnabledTest> and <enabledConfiguration> have been declared within <sso> for {}; using <ssoEnabledTest>", serviceName);
+      }
+      return PredicateUtils.fromJSON(sInfo.getSingleSignOnEnabledTest());
+    } else if (StringUtils.isNotBlank(sInfo.getSingleSignOnEnabledConfiguration())) {
+      LOG.warn("Only <enabledConfiguration> have been declared  within <sso> for {}; converting its value to an equals predicate", serviceName);
+      final String equalsPredicateJson = "{\"equals\": [\"" + sInfo.getSingleSignOnEnabledConfiguration() + "\", \"true\"]}";
+      return PredicateUtils.fromJSON(equalsPredicateJson);
+    }
+    return null;
   }
 
-  public boolean isSsoIntegrationEnabled() {
-    try {
-      return ssoIntegrationSupported && ssoEnabledConfiguration != null && ssoEnabledConfiguration.evaluate(configHelper.calculateExistingConfigurations(ambariManagementController, cluster));
-    } catch (AmbariException e) {
-      throw new AmbariRuntimeException("Error while evaulating if SSO integration is enabled", e);
+  private Predicate compileKerberosEnabledPredicate(ServiceInfo sInfo) {
+    if (StringUtils.isNotBlank(sInfo.getKerberosEnabledTest())) {
+      return PredicateUtils.fromJSON(sInfo.getKerberosEnabledTest());
     }
+    return null;
   }
 
-  private boolean isKerberosRequredForSsoIntegration() {
-    return ssoRequiresKerberos;
+  private boolean isSsoIntegrationDesired() {
+    return ambariServerConfigurationHandler.getSSOEnabledServices().contains(serviceName);
   }
 
+  private boolean isSsoIntegrationEnabled(Map<String, Map<String, String>> existingConfigurations) {
+    return ssoIntegrationSupported && ssoEnabledTest != null && ssoEnabledTest.evaluate(existingConfigurations);
+  }
+
+  private boolean isKerberosRequiredForSsoIntegration() {
+    return ssoRequiresKerberos;
+  }
 }
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 938f73b..23923e5 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
@@ -41,6 +41,7 @@ import javax.xml.bind.annotation.XmlEnumValue;
 import javax.xml.bind.annotation.XmlTransient;
 
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.collections.PredicateUtils;
 import org.apache.ambari.server.stack.StackDirectory;
 import org.apache.ambari.server.stack.Validable;
 import org.apache.ambari.server.state.stack.MetricDefinition;
@@ -152,6 +153,14 @@ public class ServiceInfo implements Validable {
   private CredentialStoreInfo credentialStoreInfo;
 
   /**
+   * The configuration that can be used to determine if Kerberos has been enabled for this service.
+   * <p>
+   * It is expected that this value is in the form of a valid JSON predicate ({@link PredicateUtils#fromJSON(String)}
+   */
+  @XmlElement(name = "kerberosEnabledTest")
+  private String kerberosEnabledTest = null;
+
+  /**
    * Single Sign-on support information
    */
   @XmlElements(@XmlElement(name = "sso"))
@@ -627,6 +636,27 @@ public class ServiceInfo implements Validable {
   }
 
   /**
+   * Gets the JSON predicate ({@link PredicateUtils#fromJSON(String)} that can be used to determine
+   * if Kerberos has been enabled for this service or not.
+   *
+   * @return a valid JSON predicate ({@link PredicateUtils#fromJSON(String)}
+   */
+  public String getKerberosEnabledTest() {
+    return kerberosEnabledTest;
+  }
+
+  /**
+   * Sets the JSON predicate ({@link PredicateUtils#fromJSON(String)} that can be used to determine
+   * if Kerberos has been enabled for this service or not.
+   *
+   * @param kerberosEnabledTest a valid JSON predicate ({@link PredicateUtils#fromJSON(String)}
+   */
+  public void setKerberosEnabledTest(String kerberosEnabledTest) {
+    this.kerberosEnabledTest = kerberosEnabledTest;
+  }
+
+
+  /**
    * Gets the value for the SSO integration support
    *
    * @return the {@link SingleSignOnInfo}
@@ -680,6 +710,8 @@ public class ServiceInfo implements Validable {
     sb.append(serviceType);
     sb.append("\nversion:");
     sb.append(version);
+    sb.append("\nKerberos enabled test:");
+    sb.append(kerberosEnabledTest);
     sb.append("\ncomment:");
     sb.append(comment);
 
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 2da5f96..5fc3426 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
@@ -790,6 +790,63 @@ public class ServiceInfoTest {
     assertNull(singleSignOnInfo.getEnabledConfiguration());
   }
 
+  /**
+   * Tests the presence and absence of the kerberosEnabledTest block.
+   */
+  @Test
+  public void testKerberosEnabledTest() throws Exception {
+    Map<String, ServiceInfo> serviceInfoMap;
+    ServiceInfo service;
+
+    String kerberosEnabledTest =
+        "{\n" +
+            "  \"or\": [\n" +
+            "    {\n" +
+            "      \"equals\": [\n" +
+            "        \"core-site/hadoop.security.authentication\",\n" +
+            "        \"kerberos\"\n" +
+            "      ]\n" +
+            "    },\n" +
+            "    {\n" +
+            "      \"equals\": [\n" +
+            "        \"hdfs-site/hadoop.security.authentication\",\n" +
+            "        \"kerberos\"\n" +
+            "      ]\n" +
+            "    }\n" +
+            "  ]\n" +
+            "}";
+
+    String serviceInfoXml = "<metainfo>\n" +
+        "  <schemaVersion>2.0</schemaVersion>\n" +
+        "  <services>\n" +
+        "    <service>\n" +
+        "      <name>HDFS</name>\n" +
+        "      <kerberosEnabledTest>\n" +
+        kerberosEnabledTest +
+        "      </kerberosEnabledTest>\n" +
+        "    </service>\n" +
+        "  </services>\n" +
+        "</metainfo>\n";
+    serviceInfoMap = getServiceInfo(serviceInfoXml);
+    service = serviceInfoMap.get("HDFS");
+    assertEquals(kerberosEnabledTest, service.getKerberosEnabledTest().trim());
+
+    /*
+     * <kerberosEnabledTest> is missing
+     */
+    serviceInfoXml = "<metainfo>\n" +
+        "  <schemaVersion>2.0</schemaVersion>\n" +
+        "  <services>\n" +
+        "    <service>\n" +
+        "      <name>HDFS</name>\n" +
+        "    </service>\n" +
+        "  </services>\n" +
+        "</metainfo>\n";
+    serviceInfoMap = getServiceInfo(serviceInfoXml);
+    service = serviceInfoMap.get("HDFS");
+    assertNull(service.getKerberosEnabledTest());
+  }
+
   private static Map<String, ServiceInfo> getServiceInfo(String xml) throws JAXBException {
     InputStream configStream = new ByteArrayInputStream(xml.getBytes());
     JAXBContext jaxbContext = JAXBContext.newInstance(ServiceMetainfoXml.class);
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/ServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/ServiceTest.java
index 5665179..3d4fbbf 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/ServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/ServiceTest.java
@@ -22,6 +22,7 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 
 import java.sql.SQLException;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -291,6 +292,61 @@ public class ServiceTest {
     Assert.assertEquals(MaintenanceState.ON, entity.getServiceDesiredStateEntity().getMaintenanceState());
   }
 
+  /**
+   * Tests the kerberosEnabledTest value set in the HDFS metainfo file (stacks/HDP/0.1/services/HDFS/metainfo.xml):
+   * <pre>
+   * {
+   *   "or": [
+   *     {
+   *       "equals": [
+   *         "core-site/hadoop.security.authentication",
+   *         "kerberos"
+   *       ]
+   *     },
+   *     {
+   *       "equals": [
+   *         "hdfs-site/hadoop.security.authentication",
+   *         "kerberos"
+   *       ]
+   *     }
+   *   ]
+   * }
+   * </pre>
+   */
+  @Test
+  public void testServiceKerberosEnabledTest() throws Exception {
+    String serviceName = "HDFS";
+    Service s = serviceFactory.createNew(cluster, serviceName, repositoryVersion);
+    cluster.addService(s);
+
+    Service service = cluster.getService(serviceName);
+    Assert.assertNotNull(service);
+
+
+    Map<String, Map<String, String>> map = new HashMap<>();
+
+    Assert.assertFalse(service.isKerberosEnabled(null));
+
+    Assert.assertFalse(service.isKerberosEnabled(map));
+
+    map.put("core-site", Collections.singletonMap("hadoop.security.authentication", "none"));
+    map.put("hdfs-site", Collections.singletonMap("hadoop.security.authentication", "none"));
+    Assert.assertFalse(service.isKerberosEnabled(map));
+
+    map.put("core-site", Collections.singletonMap("hadoop.security.authentication", "kerberos"));
+    map.put("hdfs-site", Collections.singletonMap("hadoop.security.authentication", "none"));
+    Assert.assertTrue(service.isKerberosEnabled(map));
+
+    map.put("core-site", Collections.singletonMap("hadoop.security.authentication", "none"));
+    map.put("hdfs-site", Collections.singletonMap("hadoop.security.authentication", "kerberos"));
+    Assert.assertTrue(service.isKerberosEnabled(map));
+
+    map.put("core-site", Collections.singletonMap("hadoop.security.authentication", "kerberos"));
+    map.put("hdfs-site", Collections.singletonMap("hadoop.security.authentication", "kerberos"));
+    Assert.assertTrue(service.isKerberosEnabled(map));
+
+  }
+
   private void addHostToCluster(String hostname,
                                 String clusterName) throws AmbariException {
     clusters.addHost(hostname);
diff --git a/ambari-server/src/test/resources/stacks/HDP/0.1/services/HDFS/metainfo.xml b/ambari-server/src/test/resources/stacks/HDP/0.1/services/HDFS/metainfo.xml
index 7629552..338b0f6 100644
--- a/ambari-server/src/test/resources/stacks/HDP/0.1/services/HDFS/metainfo.xml
+++ b/ambari-server/src/test/resources/stacks/HDP/0.1/services/HDFS/metainfo.xml
@@ -151,6 +151,25 @@
         <config-type>hadoop-policy</config-type>
         <config-type>hdfs-log4j</config-type>
       </configuration-dependencies>
+
+      <kerberosEnabledTest>
+        {
+        "or": [
+        {
+        "equals": [
+        "core-site/hadoop.security.authentication",
+        "kerberos"
+        ]
+        },
+        {
+        "equals": [
+        "hdfs-site/hadoop.security.authentication",
+        "kerberos"
+        ]
+        }
+        ]
+        }
+      </kerberosEnabledTest>
     </service>
   </services>
 </metainfo>