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

rlevas 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 c897c68  [AMBARI-23252] Update service metainfo to declare SSO 
integration support
c897c68 is described below

commit c897c680d0e137c19931def70d3051dcaafe8749
Author: Robert Levas <[email protected]>
AuthorDate: Sat Mar 17 10:38:28 2018 -0400

    [AMBARI-23252] Update service metainfo to declare SSO integration support
    
    * [AMBARI-23252] Update service metainfo to declare SSO integration support
    
    * [AMBARI-23252] Update service metainfo to declare SSO integration support
    
    * [AMBARI-23252] Update service metainfo to declare SSO integration support
---
 .../apache/ambari/server/stack/ServiceModule.java  |   8 +
 .../apache/ambari/server/state/ServiceInfo.java    | 194 ++++--
 .../ambari/server/state/SingleSignOnInfo.java      | 133 ++++
 .../ambari/server/stack/ServiceModuleTest.java     |  45 ++
 .../ambari/server/state/ServiceInfoTest.java       | 692 ++++++++++++---------
 5 files changed, 708 insertions(+), 364 deletions(-)

diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceModule.java 
b/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceModule.java
index 4eb3858..9189ff8 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceModule.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/stack/ServiceModule.java
@@ -285,6 +285,14 @@ public class ServiceModule extends 
BaseModule<ServiceModule, ServiceInfo> implem
       serviceInfo.setCredentialStoreInfo(parent.getCredentialStoreInfo());
     }
 
+    /*
+     * If current stack version does not specify the single sign-on support 
details for the service,
+     * then use parent definition.
+     */
+    if (serviceInfo.getSingleSignOnInfo() == null) {
+      serviceInfo.setSingleSignOnInfo(parent.getSingleSignOnInfo());
+    }
+
     if (serviceInfo.isSelectionEmpty()) {
       serviceInfo.setSelection(parent.getSelection());
     }
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 8f27132..6ac5f4e 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
@@ -45,6 +45,7 @@ import org.apache.ambari.server.stack.StackDirectory;
 import org.apache.ambari.server.stack.Validable;
 import org.apache.ambari.server.state.stack.MetricDefinition;
 import org.apache.ambari.server.state.stack.StackRoleCommandOrder;
+import org.apache.commons.lang.StringUtils;
 import org.codehaus.jackson.annotate.JsonIgnore;
 import org.codehaus.jackson.map.annotate.JsonFilter;
 
@@ -57,7 +58,7 @@ import com.google.common.collect.Multimaps;
 
 @XmlAccessorType(XmlAccessType.FIELD)
 @JsonFilter("propertiesfilter")
-public class ServiceInfo implements Validable{
+public class ServiceInfo implements Validable {
 
   public static final AbstractMap.SimpleEntry<String, String> 
DEFAULT_SERVICE_INSTALLABLE_PROPERTY = new 
AbstractMap.SimpleEntry<>("installable", "true");
   public static final AbstractMap.SimpleEntry<String, String> 
DEFAULT_SERVICE_MANAGED_PROPERTY = new AbstractMap.SimpleEntry<>("managed", 
"true");
@@ -87,20 +88,21 @@ public class ServiceInfo implements Validable{
     @XmlEnumValue("JAVA")
     JAVA
   }
-  @XmlElement(name="service_advisor_type")
+
+  @XmlElement(name = "service_advisor_type")
   private ServiceAdvisorType serviceAdvisorType = ServiceAdvisorType.PYTHON;
 
   @XmlTransient
   private List<PropertyInfo> properties;
 
-  @XmlElementWrapper(name="components")
-  @XmlElements(@XmlElement(name="component"))
+  @XmlElementWrapper(name = "components")
+  @XmlElements(@XmlElement(name = "component"))
   private List<ComponentInfo> components;
 
-  @XmlElement(name="deleted")
+  @XmlElement(name = "deleted")
   private boolean isDeleted = false;
 
-  @XmlElement(name="supportDeleteViaUI")
+  @XmlElement(name = "supportDeleteViaUI")
   private Boolean supportDeleteViaUIField;
 
   private boolean supportDeleteViaUIInternal = true;
@@ -109,12 +111,12 @@ public class ServiceInfo implements Validable{
   @XmlTransient
   private volatile Map<String, Set<String>> configLayout = null;
 
-  @XmlElementWrapper(name="configuration-dependencies")
-  @XmlElement(name="config-type")
+  @XmlElementWrapper(name = "configuration-dependencies")
+  @XmlElement(name = "config-type")
   private List<String> configDependencies;
 
-  @XmlElementWrapper(name="excluded-config-types")
-  @XmlElement(name="config-type")
+  @XmlElementWrapper(name = "excluded-config-types")
+  @XmlElement(name = "config-type")
   private Set<String> excludedConfigTypes = new HashSet<>();
 
   @XmlTransient
@@ -149,6 +151,12 @@ public class ServiceInfo implements Validable{
   @XmlElements(@XmlElement(name = "credential-store"))
   private CredentialStoreInfo credentialStoreInfo;
 
+  /**
+   * Single Sign-on support information
+   */
+  @XmlElements(@XmlElement(name = "sso"))
+  private SingleSignOnInfo singleSignOnInfo;
+
   public Boolean isRestartRequiredAfterChange() {
     return restartRequiredAfterChange;
   }
@@ -184,14 +192,13 @@ public class ServiceInfo implements Validable{
   private boolean valid = true;
 
   @XmlElementWrapper(name = "properties")
-  @XmlElement(name="property")
+  @XmlElement(name = "property")
   private List<ServicePropertyInfo> servicePropertyList = Lists.newArrayList();
 
   @XmlTransient
   private Map<String, String> servicePropertyMap = 
ImmutableMap.copyOf(ensureMandatoryServiceProperties(Maps.newHashMap()));
 
   /**
-   *
    * @return valid xml flag
    */
   @Override
@@ -200,7 +207,6 @@ public class ServiceInfo implements Validable{
   }
 
   /**
-   *
    * @param valid set validity flag
    */
   @Override
@@ -225,16 +231,17 @@ public class ServiceInfo implements Validable{
   public void addErrors(Collection<String> errors) {
     this.errorSet.addAll(errors);
   }
+
   /**
    * Internal list of os-specific details (loaded from xml). Added at schema 
ver 2
    */
   @JsonIgnore
-  @XmlElementWrapper(name="osSpecifics")
-  @XmlElements(@XmlElement(name="osSpecific"))
+  @XmlElementWrapper(name = "osSpecifics")
+  @XmlElements(@XmlElement(name = "osSpecific"))
   private List<ServiceOsSpecific> serviceOsSpecifics;
 
   @JsonIgnore
-  @XmlElement(name="configuration-dir")
+  @XmlElement(name = "configuration-dir")
   private String configDir = StackDirectory.SERVICE_CONFIG_FOLDER_NAME;
 
   @JsonIgnore
@@ -277,12 +284,12 @@ public class ServiceInfo implements Validable{
   /**
    * Added at schema ver 2
    */
-  @XmlElementWrapper(name="customCommands")
-  @XmlElements(@XmlElement(name="customCommand"))
+  @XmlElementWrapper(name = "customCommands")
+  @XmlElements(@XmlElement(name = "customCommand"))
   private List<CustomCommandDefinition> customCommands;
 
-  @XmlElementWrapper(name="requiredServices")
-  @XmlElement(name="service")
+  @XmlElementWrapper(name = "requiredServices")
+  @XmlElement(name = "service")
   private List<String> requiredServices = new ArrayList<>();
 
   /**
@@ -320,7 +327,7 @@ public class ServiceInfo implements Validable{
     isDeleted = deleted;
   }
 
-  public Boolean getSupportDeleteViaUIField(){
+  public Boolean getSupportDeleteViaUIField() {
     return supportDeleteViaUIField;
   }
 
@@ -337,7 +344,7 @@ public class ServiceInfo implements Validable{
     return this.supportDeleteViaUIInternal;
   }
 
-  public void setSupportDeleteViaUI(boolean supportDeleteViaUI){
+  public void setSupportDeleteViaUI(boolean supportDeleteViaUI) {
     this.supportDeleteViaUIInternal = supportDeleteViaUI;
   }
 
@@ -374,11 +381,11 @@ public class ServiceInfo implements Validable{
   }
 
   public String getServiceType() {
-       return serviceType;
+    return serviceType;
   }
 
   public void setServiceType(String serviceType) {
-       this.serviceType = serviceType;
+    this.serviceType = serviceType;
   }
 
   public String getVersion() {
@@ -403,6 +410,7 @@ public class ServiceInfo implements Validable{
   /**
    * Check if selection was presented in xml. We need this for proper stack 
inheritance, because {@link ServiceInfo#getSelection}
    * by default returns {@link Selection#DEFAULT}, even if no value found in 
metainfo.xml.
+   *
    * @return true, if selection not defined in metainfo.xml
    */
   public boolean isSelectionEmpty() {
@@ -416,6 +424,7 @@ public class ServiceInfo implements Validable{
   public void setComment(String comment) {
     this.comment = comment;
   }
+
   public List<String> getRequiredServices() {
     return requiredServices;
   }
@@ -439,8 +448,11 @@ public class ServiceInfo implements Validable{
   public void setRequiredServices(List<String> requiredServices) {
     this.requiredServices = requiredServices;
   }
+
   public List<PropertyInfo> getProperties() {
-    if (properties == null) properties = new ArrayList<>();
+    if (properties == null) {
+      properties = new ArrayList<>();
+    }
     return properties;
   }
 
@@ -449,23 +461,27 @@ public class ServiceInfo implements Validable{
   }
 
   public List<ComponentInfo> getComponents() {
-    if (components == null) components = new ArrayList<>();
+    if (components == null) {
+      components = new ArrayList<>();
+    }
     return components;
   }
 
   /**
    * Finds ComponentInfo by component name
-   * @param componentName  name of the component
+   *
+   * @param componentName name of the component
    * @return ComponentInfo componentName or null
    */
-  public ComponentInfo getComponentByName(String componentName){
-    for(ComponentInfo componentInfo : getComponents()) {
-      if(componentInfo.getName().equals(componentName)){
+  public ComponentInfo getComponentByName(String componentName) {
+    for (ComponentInfo componentInfo : getComponents()) {
+      if (componentInfo.getName().equals(componentName)) {
         return componentInfo;
       }
     }
     return null;
   }
+
   public boolean isClientOnlyService() {
     if (components == null || components.isEmpty()) {
       return false;
@@ -526,6 +542,7 @@ public class ServiceInfo implements Validable{
 
   /**
    * Set a value indicating if this service supports credential store.
+   *
    * @param credentialStoreSupported
    */
   public void setCredentialStoreSupported(boolean credentialStoreSupported) {
@@ -553,6 +570,7 @@ public class ServiceInfo implements Validable{
 
   /**
    * Set a value indicating if this service requires credential store.
+   *
    * @param credentialStoreRequired
    */
   public void setCredentialStoreRequired(boolean credentialStoreRequired) {
@@ -580,6 +598,7 @@ public class ServiceInfo implements Validable{
 
   /**
    * Set a value indicating if this service is enabled for credential store 
use.
+   *
    * @param credentialStoreEnabled
    */
   public void setCredentialStoreEnabled(boolean credentialStoreEnabled) {
@@ -607,6 +626,33 @@ public class ServiceInfo implements Validable{
     this.credentialStoreInfo = credentialStoreInfo;
   }
 
+  /**
+   * Gets the value for the SSO integration support
+   *
+   * @return the {@link SingleSignOnInfo}
+   */
+  public SingleSignOnInfo getSingleSignOnInfo() {
+    return singleSignOnInfo;
+  }
+
+  /**
+   * Set a new value for the SSO integration support
+   *
+   * @param singleSignOnInfo a {@link SingleSignOnInfo}
+   */
+  public void setSingleSignOnInfo(SingleSignOnInfo singleSignOnInfo) {
+    this.singleSignOnInfo = singleSignOnInfo;
+  }
+
+  /**
+   * Indicates if this service supports single sign-on integration.
+   *
+   * @return true or false
+   */
+  public boolean isSingleSignOnSupported() {
+    return (singleSignOnInfo != null) && singleSignOnInfo.isSupported();
+  }
+
   @Override
   public String toString() {
     StringBuilder sb = new StringBuilder();
@@ -637,13 +683,14 @@ public class ServiceInfo implements Validable{
   /**
    * Obtain the config types associated with this service.
    * The returned map is an unmodifiable view.
+   *
    * @return unmodifiable map of config types associated with this service
    */
   public synchronized Map<String, Map<String, Map<String, String>>> 
getConfigTypeAttributes() {
     Map<String, Map<String, Map<String, String>>> tmpConfigTypes = configTypes 
== null ?
-      new HashMap<>() : configTypes;
+        new HashMap<>() : configTypes;
 
-    for(String excludedtype : excludedConfigTypes){
+    for (String excludedtype : excludedConfigTypes) {
       tmpConfigTypes.remove(excludedtype);
     }
 
@@ -654,8 +701,8 @@ public class ServiceInfo implements Validable{
    * Add the given type and set it's attributes.
    * If the type is marked for exclusion, it will not be added.
    *
-   * @param type            configuration type
-   * @param typeAttributes  attributes associated with the type
+   * @param type           configuration type
+   * @param typeAttributes attributes associated with the type
    */
   public synchronized void setTypeAttributes(String type, Map<String, 
Map<String, String>> typeAttributes) {
     if (this.configTypes == null) {
@@ -679,6 +726,7 @@ public class ServiceInfo implements Validable{
 
   /**
    * Determine of the service has a dependency on the provided configuration 
type.
+   *
    * @param type the config type
    * @return <code>true</code> if the service defines a dependency on the 
provided type
    */
@@ -688,7 +736,8 @@ public class ServiceInfo implements Validable{
 
   /**
    * Determine if the service contains the specified config type
-   * @param type  config type to check
+   *
+   * @param type config type to check
    * @return true if the service has the specified config type; false otherwise
    */
   public boolean hasConfigType(String type) {
@@ -699,21 +748,23 @@ public class ServiceInfo implements Validable{
   /**
    * Determine if the service has a dependency on the provided type and 
contains any of the provided properties.
    * This can be used in determining if a property is stale.
-
-   * @param type the config type
+   *
+   * @param type     the config type
    * @param keyNames the names of all the config keys for the given type
    * @return <code>true</code> if the config is stale
    */
   public boolean hasDependencyAndPropertyFor(String type, Collection<String> 
keyNames) {
-    if (!hasConfigDependency(type))
+    if (!hasConfigDependency(type)) {
       return false;
+    }
 
     buildConfigLayout();
     Set<String> keys = configLayout.get(type);
 
     for (String staleCheck : keyNames) {
-      if (keys != null && keys.contains(staleCheck))
+      if (keys != null && keys.contains(staleCheck)) {
         return true;
+      }
     }
 
     return false;
@@ -724,7 +775,7 @@ public class ServiceInfo implements Validable{
    */
   private void buildConfigLayout() {
     if (null == configLayout) {
-      synchronized(this) {
+      synchronized (this) {
         if (null == configLayout) {
           configLayout = new HashMap<>();
 
@@ -733,8 +784,9 @@ public class ServiceInfo implements Validable{
             int idx = type.indexOf(".xml");
             type = type.substring(0, idx);
 
-            if (!configLayout.containsKey(type))
+            if (!configLayout.containsKey(type)) {
               configLayout.put(type, new HashSet<>());
+            }
 
             configLayout.get(type).add(pi.getName());
           }
@@ -746,14 +798,15 @@ public class ServiceInfo implements Validable{
   public List<String> getConfigDependencies() {
     return configDependencies;
   }
-  public List<String> getConfigDependenciesWithComponents(){
+
+  public List<String> getConfigDependenciesWithComponents() {
     List<String> retVal = new ArrayList<>();
-    if(configDependencies != null){
+    if (configDependencies != null) {
       retVal.addAll(configDependencies);
     }
-    if(components != null){
+    if (components != null) {
       for (ComponentInfo c : components) {
-        if(c.getConfigDependencies() != null){
+        if (c.getConfigDependencies() != null) {
           retVal.addAll(c.getConfigDependencies());
         }
       }
@@ -813,14 +866,15 @@ public class ServiceInfo implements Validable{
 
   /**
    * Exposes (and initializes on first use) map of os-specific details.
-   * @return  map of OS specific details keyed by family
+   *
+   * @return map of OS specific details keyed by family
    */
   public Map<String, ServiceOsSpecific> getOsSpecifics() {
     if (serviceOsSpecificsMap == null) {
       synchronized (this) { // Double-checked locking pattern
         if (serviceOsSpecificsMap == null) {
           Map<String, ServiceOsSpecific> tmpMap =
-            new TreeMap<>();
+              new TreeMap<>();
           if (serviceOsSpecifics != null) {
             for (ServiceOsSpecific osSpecific : serviceOsSpecifics) {
               tmpMap.put(osSpecific.getOsFamily(), osSpecific);
@@ -967,7 +1021,7 @@ public class ServiceInfo implements Validable{
   public Map<String, PropertyInfo> getRequiredProperties() {
     Map<String, PropertyInfo> result = requiredProperties;
     if (result == null) {
-      synchronized(this) {
+      synchronized (this) {
         result = requiredProperties;
         if (result == null) {
           requiredProperties = result = new HashMap<>();
@@ -995,7 +1049,7 @@ public class ServiceInfo implements Validable{
   /**
    * Set indicator for required restart after a host rack info change.
    *
-   * @param restartRequiredAfterRackChange  true if a restart is required
+   * @param restartRequiredAfterRackChange true if a restart is required
    */
   public void setRestartRequiredAfterRackChange(Boolean 
restartRequiredAfterRackChange) {
     this.restartRequiredAfterRackChange = restartRequiredAfterRackChange;
@@ -1077,7 +1131,7 @@ public class ServiceInfo implements Validable{
     afterServicePropertyListSet();
   }
 
-  private void afterServicePropertyListSet(){
+  private void afterServicePropertyListSet() {
     validateServiceProperties();
     buildServiceProperties();
   }
@@ -1085,9 +1139,10 @@ public class ServiceInfo implements Validable{
 
   /**
    * Returns the service properties defined in the xml service definition.
+   *
    * @return Service property map
    */
-  public Map<String, String> getServiceProperties()  {
+  public Map<String, String> getServiceProperties() {
     return servicePropertyMap;
   }
 
@@ -1103,9 +1158,9 @@ public class ServiceInfo implements Validable{
         properties.put(property.getName(), property.getValue());
       }
       servicePropertyMap = 
ImmutableMap.copyOf(ensureMandatoryServiceProperties(properties));
-    }
-    else
+    } else {
       servicePropertyMap = ImmutableMap.of();
+    }
 
 
   }
@@ -1115,15 +1170,18 @@ public class ServiceInfo implements Validable{
   }
 
   private Map<String, String> ensureVisibilityServiceProperties(Map<String, 
String> properties) {
-    if (!properties.containsKey(DEFAULT_SERVICE_INSTALLABLE_PROPERTY.getKey()))
+    if 
(!properties.containsKey(DEFAULT_SERVICE_INSTALLABLE_PROPERTY.getKey())) {
       properties.put(DEFAULT_SERVICE_INSTALLABLE_PROPERTY.getKey(), 
DEFAULT_SERVICE_INSTALLABLE_PROPERTY.getValue());
+    }
 
-    if (!properties.containsKey(DEFAULT_SERVICE_MANAGED_PROPERTY.getKey()))
+    if (!properties.containsKey(DEFAULT_SERVICE_MANAGED_PROPERTY.getKey())) {
       properties.put(DEFAULT_SERVICE_MANAGED_PROPERTY.getKey(), 
DEFAULT_SERVICE_MANAGED_PROPERTY.getValue());
+    }
 
 
-    if (!properties.containsKey(DEFAULT_SERVICE_MONITORED_PROPERTY.getKey()))
+    if (!properties.containsKey(DEFAULT_SERVICE_MONITORED_PROPERTY.getKey())) {
       properties.put(DEFAULT_SERVICE_MONITORED_PROPERTY.getKey(), 
DEFAULT_SERVICE_MONITORED_PROPERTY.getValue());
+    }
 
     return properties;
   }
@@ -1136,17 +1194,17 @@ public class ServiceInfo implements Validable{
   private void validateServiceProperties() {
     // Verify if there are duplicate service properties by name
     Multimap<String, ServicePropertyInfo> servicePropsByName = Multimaps.index(
-      getServicePropertyList(),
-      new Function<ServicePropertyInfo, String>() {
-        @Override
-        public String apply(ServicePropertyInfo servicePropertyInfo) {
-          return servicePropertyInfo.getName();
+        getServicePropertyList(),
+        new Function<ServicePropertyInfo, String>() {
+          @Override
+          public String apply(ServicePropertyInfo servicePropertyInfo) {
+            return servicePropertyInfo.getName();
+          }
         }
-      }
 
     );
 
-    for (String propertyName: servicePropsByName.keySet()) {
+    for (String propertyName : servicePropsByName.keySet()) {
       if (servicePropsByName.get(propertyName).size() > 1) {
         setValid(false);
         addError("Duplicate service property with name '" + propertyName + "' 
found in " + getName() + ":" + getVersion() + " service definition !");
@@ -1187,6 +1245,16 @@ public class ServiceInfo implements Validable{
         addError("Credential store enabled is not specified for service " + 
getName());
       }
     }
+
+    // validate single sign-in support information
+    if (singleSignOnInfo != null) {
+      if (singleSignOnInfo.isSupported()) {
+        if (StringUtils.isEmpty(singleSignOnInfo.getEnabledConfiguration())) {
+          setValid(false);
+          addError("Single Sign-on support is indicated for service " + 
getName() + " but no test configuration has been set (enabledConfiguration).");
+        }
+      }
+    }
   }
 
   public enum Selection {
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/state/SingleSignOnInfo.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/state/SingleSignOnInfo.java
new file mode 100644
index 0000000..ecaa504
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/state/SingleSignOnInfo.java
@@ -0,0 +1,133 @@
+/*
+ * 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 com.google.common.base.MoreObjects;
+
+/**
+ * {@link SingleSignOnInfo} encapsulates meta information about a service's 
support for single
+ * sign-on (SSO) integration
+ * <p>
+ * The data is expected to be like
+ * <pre>
+ *   &lt;sso&gt;
+ *     &lt;supported&gt;true&lt;/supported&gt;
+ *     
&lt;enabledConfiguration&gt;config-type/sso.enabled.property_name&lt;/enabledConfiguration&gt;
+ *   &lt;/sso&gt;
+ * </pre>
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+public class SingleSignOnInfo {
+
+  /**
+   * Indicates whether the relevant service supports SSO 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 SSO integration has 
been enabled.
+   * <p>
+   * It is expected that this value is in the form of 
<code>configuration-type/property_name</code>
+   */
+  @XmlElement(name = "enabledConfiguration")
+  private String enabledConfiguration = null;
+
+  /**
+   * Default constructor
+   */
+  public SingleSignOnInfo() {
+  }
+
+  /**
+   * 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 SSO integration is supported; false 
otherwise
+   * @param enabledConfiguration the configuration that can be used to 
determine if SSO integration has been enabled
+   */
+  public SingleSignOnInfo(Boolean supported, String enabledConfiguration) {
+    this.supported = supported;
+    this.enabledConfiguration = enabledConfiguration;
+  }
+
+  /**
+   * Tests whether the service supports SSO integration.
+   *
+   * @return true if SSO integration is supported; false otherwise
+   */
+  public boolean isSupported() {
+    return Boolean.TRUE.equals(supported);
+  }
+
+  /**
+   * Gets the value whether if the service supports SSO integration.
+   * <p>
+   * <code>null</code> indicates the value was not set
+   *
+   * @return true if SSO integration is supported; false if SSO integration is 
not supported; null if not specified
+   */
+  public Boolean getSupported() {
+    return supported;
+  }
+
+  /**
+   * Gets the value indicating whether the service supports SSO integration.
+   *
+   * @param supported true if SSO integration is supported; false if SSO 
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 SSO 
has been enabled or not.
+   *
+   * @return a configuration specification (config-type/property_name)
+   */
+  public String getEnabledConfiguration() {
+    return enabledConfiguration;
+  }
+
+  /**
+   * Sets the configuration specification that can be used to determine if SSO 
has been enabled or not.
+   *
+   * @param enabledConfiguration a configuration specification 
(config-type/property_name)
+   */
+  public void setEnabledConfiguration(String enabledConfiguration) {
+    this.enabledConfiguration = enabledConfiguration;
+  }
+
+  /**
+   * String representation of this object
+   *
+   * @return a string
+   */
+  @Override
+  public String toString() {
+    return MoreObjects.toStringHelper(this)
+        .add("supported", supported)
+        .add("enabledConfiguration", enabledConfiguration)
+        .toString();
+  }
+}
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/stack/ServiceModuleTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/stack/ServiceModuleTest.java
index 13c32cf..ee36443 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/stack/ServiceModuleTest.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/stack/ServiceModuleTest.java
@@ -48,6 +48,7 @@ import org.apache.ambari.server.state.PropertyInfo;
 import org.apache.ambari.server.state.ServiceInfo;
 import org.apache.ambari.server.state.ServiceOsSpecific;
 import org.apache.ambari.server.state.ServicePropertyInfo;
+import org.apache.ambari.server.state.SingleSignOnInfo;
 import org.junit.Test;
 
 import com.google.common.collect.ImmutableMap;
@@ -1069,6 +1070,50 @@ public class ServiceModuleTest {
     assertEquals(credentialStoreInfoChild.isEnabled(), 
service.getModuleInfo().isCredentialStoreEnabled());
     assertEquals(credentialStoreInfoChild.isRequired(), 
service.getModuleInfo().isCredentialStoreRequired());
   }
+  /**
+   * Verify stack resolution for single sign-on details
+   *
+   * @throws Exception
+   */
+  @Test
+  public void testResolve_SingleSignOnInfo() throws Exception {
+    SingleSignOnInfo singleSignOnInfoChild = new SingleSignOnInfo(false, null);
+    SingleSignOnInfo singleSignOnInfoParent = new SingleSignOnInfo(true, 
"config-type/property_name");
+    ServiceInfo childInfo = new ServiceInfo();
+    ServiceInfo parentInfo = new ServiceInfo();
+    ServiceModule serviceModule;
+    ServiceInfo serviceInfo;
+
+    // specified in child only, child wins
+    childInfo.setSingleSignOnInfo(singleSignOnInfoChild);
+    parentInfo.setSingleSignOnInfo(null);
+    serviceModule = resolveService(childInfo, parentInfo);
+    serviceInfo = serviceModule.getModuleInfo();
+    assertEquals(singleSignOnInfoChild.isSupported(), 
serviceInfo.isSingleSignOnSupported());
+    assertEquals(singleSignOnInfoChild.isSupported(), 
serviceInfo.getSingleSignOnInfo().isSupported());
+    assertEquals(singleSignOnInfoChild.getSupported(), 
serviceInfo.getSingleSignOnInfo().getSupported());
+    assertEquals(singleSignOnInfoChild.getEnabledConfiguration(), 
serviceInfo.getSingleSignOnInfo().getEnabledConfiguration());
+
+    // specified in parent only, parent wins
+    childInfo.setSingleSignOnInfo(null);
+    parentInfo.setSingleSignOnInfo(singleSignOnInfoParent);
+    serviceModule = resolveService(childInfo, parentInfo);
+    serviceInfo = serviceModule.getModuleInfo();
+    assertEquals(singleSignOnInfoParent.isSupported(), 
serviceInfo.isSingleSignOnSupported());
+    assertEquals(singleSignOnInfoParent.isSupported(), 
serviceInfo.getSingleSignOnInfo().isSupported());
+    assertEquals(singleSignOnInfoParent.getSupported(), 
serviceInfo.getSingleSignOnInfo().getSupported());
+    assertEquals(singleSignOnInfoParent.getEnabledConfiguration(), 
serviceInfo.getSingleSignOnInfo().getEnabledConfiguration());
+
+    // specified in both, child wins
+    childInfo.setSingleSignOnInfo(singleSignOnInfoChild);
+    parentInfo.setSingleSignOnInfo(singleSignOnInfoParent);
+    serviceModule = resolveService(childInfo, parentInfo);
+    serviceInfo = serviceModule.getModuleInfo();
+    assertEquals(singleSignOnInfoChild.isSupported(), 
serviceInfo.isSingleSignOnSupported());
+    assertEquals(singleSignOnInfoChild.isSupported(), 
serviceInfo.getSingleSignOnInfo().isSupported());
+    assertEquals(singleSignOnInfoChild.getSupported(), 
serviceInfo.getSingleSignOnInfo().getSupported());
+    assertEquals(singleSignOnInfoChild.getEnabledConfiguration(), 
serviceInfo.getSingleSignOnInfo().getEnabledConfiguration());
+  }
 
   @Test
   public void testServiceCheckRegistered() throws Exception {
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 ee648a9..e5843ce 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
@@ -20,6 +20,7 @@ package org.apache.ambari.server.state;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
@@ -78,35 +79,35 @@ public class ServiceInfoTest {
         "    </service>\n" +
         "  </services>\n" +
         "</metainfo>\n";
-    
+
     Map<String, ServiceInfo> serviceInfoMap = getServiceInfo(serviceInfoXml);
 
     
assertTrue(serviceInfoMap.get("RESTART").isRestartRequiredAfterRackChange());
     
assertFalse(serviceInfoMap.get("NO_RESTART").isRestartRequiredAfterRackChange());
     
assertNull(serviceInfoMap.get("DEFAULT_RESTART").isRestartRequiredAfterRackChange());
-    assertEquals(serviceInfoMap.get("HCFS_SERVICE").getServiceType(),"HCFS");
+    assertEquals(serviceInfoMap.get("HCFS_SERVICE").getServiceType(), "HCFS");
   }
 
   @Test
   public void testCustomMetricsWidgetsFiles() throws Exception {
 
     String serviceInfoXml = "<metainfo>\n" +
-            "  <schemaVersion>2.0</schemaVersion>\n" +
-            "  <services>\n" +
-            "    <service>\n" +
-            "      <name>CUSTOM</name>\n" +
-            "      <displayName>CUSTOM</displayName>\n" +
-            "      <metricsFileName>CUSTOM_metrics.json</metricsFileName>\n" +
-            "      <widgetsFileName>CUSTOM_widgets.json</widgetsFileName>\n" +
-            "    </service>\n" +
-            "    <service>\n" +
-            "      <name>DEFAULT</name>\n" +
-            "      <displayName>DEFAULT</displayName>\n" +
-            "      <comment>Apache Hadoop Distributed File System</comment>\n" 
+
-            "      <version>2.1.0.2.0</version>\n" +
-            "    </service>\n" +
-            "  </services>\n" +
-            "</metainfo>\n";
+        "  <schemaVersion>2.0</schemaVersion>\n" +
+        "  <services>\n" +
+        "    <service>\n" +
+        "      <name>CUSTOM</name>\n" +
+        "      <displayName>CUSTOM</displayName>\n" +
+        "      <metricsFileName>CUSTOM_metrics.json</metricsFileName>\n" +
+        "      <widgetsFileName>CUSTOM_widgets.json</widgetsFileName>\n" +
+        "    </service>\n" +
+        "    <service>\n" +
+        "      <name>DEFAULT</name>\n" +
+        "      <displayName>DEFAULT</displayName>\n" +
+        "      <comment>Apache Hadoop Distributed File System</comment>\n" +
+        "      <version>2.1.0.2.0</version>\n" +
+        "    </service>\n" +
+        "  </services>\n" +
+        "</metainfo>\n";
 
     Map<String, ServiceInfo> serviceInfoMap = getServiceInfo(serviceInfoXml);
 
@@ -148,26 +149,27 @@ public class ServiceInfoTest {
 
   /**
    * Tests the presence and absence of the credential-store block.
+   *
    * @throws Exception
-     */
+   */
   @Test
   public void testCredentialStoreFields() throws Exception {
     /*
      * <credential-store> supported and enabled.
      */
     String serviceInfoXml = "<metainfo>\n" +
-            "  <schemaVersion>2.0</schemaVersion>\n" +
-            "  <services>\n" +
-            "    <service>\n" +
-            "      <name>RANGER</name>\n" +
-            "      <credential-store>\n" +
-            "          <supported>true</supported>\n" +
-            "          <enabled>true</enabled>\n" +
-            "          <required>true</required>\n" +
-            "      </credential-store>\n" +
-            "    </service>\n" +
-            "  </services>\n" +
-            "</metainfo>\n";
+        "  <schemaVersion>2.0</schemaVersion>\n" +
+        "  <services>\n" +
+        "    <service>\n" +
+        "      <name>RANGER</name>\n" +
+        "      <credential-store>\n" +
+        "          <supported>true</supported>\n" +
+        "          <enabled>true</enabled>\n" +
+        "          <required>true</required>\n" +
+        "      </credential-store>\n" +
+        "    </service>\n" +
+        "  </services>\n" +
+        "</metainfo>\n";
     Map<String, ServiceInfo> serviceInfoMap = getServiceInfo(serviceInfoXml);
     ServiceInfo service = serviceInfoMap.get("RANGER");
     assertTrue(service.isCredentialStoreSupported());
@@ -178,18 +180,18 @@ public class ServiceInfoTest {
      * <credential-store> supported but not enabled.
      */
     serviceInfoXml = "<metainfo>\n" +
-            "  <schemaVersion>2.0</schemaVersion>\n" +
-            "  <services>\n" +
-            "    <service>\n" +
-            "      <name>HIVE</name>\n" +
-            "      <credential-store>\n" +
-            "          <supported>true</supported>\n" +
-            "          <enabled>false</enabled>\n" +
-            "          <required>false</required>\n" +
-            "      </credential-store>\n" +
-            "    </service>\n" +
-            "  </services>\n" +
-            "</metainfo>\n";
+        "  <schemaVersion>2.0</schemaVersion>\n" +
+        "  <services>\n" +
+        "    <service>\n" +
+        "      <name>HIVE</name>\n" +
+        "      <credential-store>\n" +
+        "          <supported>true</supported>\n" +
+        "          <enabled>false</enabled>\n" +
+        "          <required>false</required>\n" +
+        "      </credential-store>\n" +
+        "    </service>\n" +
+        "  </services>\n" +
+        "</metainfo>\n";
     serviceInfoMap = getServiceInfo(serviceInfoXml);
     service = serviceInfoMap.get("HIVE");
     assertTrue(service.isCredentialStoreSupported());
@@ -200,13 +202,13 @@ public class ServiceInfoTest {
      * <credential-store> is missing
      */
     serviceInfoXml = "<metainfo>\n" +
-            "  <schemaVersion>2.0</schemaVersion>\n" +
-            "  <services>\n" +
-            "    <service>\n" +
-            "      <name>AMBARI_METRICS</name>\n" +
-            "    </service>\n" +
-            "  </services>\n" +
-            "</metainfo>\n";
+        "  <schemaVersion>2.0</schemaVersion>\n" +
+        "  <services>\n" +
+        "    <service>\n" +
+        "      <name>AMBARI_METRICS</name>\n" +
+        "    </service>\n" +
+        "  </services>\n" +
+        "</metainfo>\n";
     serviceInfoMap = getServiceInfo(serviceInfoXml);
     service = serviceInfoMap.get("AMBARI_METRICS");
     assertFalse(service.isCredentialStoreSupported());
@@ -217,16 +219,16 @@ public class ServiceInfoTest {
      * scenario. So both values should be false.
      */
     serviceInfoXml = "<metainfo>\n" +
-            "  <schemaVersion>2.0</schemaVersion>\n" +
-            "  <services>\n" +
-            "    <service>\n" +
-            "      <name>HBASE</name>\n" +
-            "      <credential-store>\n" +
-            "          <supported>true</supported>\n" +
-            "      </credential-store>\n" +
-            "    </service>\n" +
-            "  </services>\n" +
-            "</metainfo>\n";
+        "  <schemaVersion>2.0</schemaVersion>\n" +
+        "  <services>\n" +
+        "    <service>\n" +
+        "      <name>HBASE</name>\n" +
+        "      <credential-store>\n" +
+        "          <supported>true</supported>\n" +
+        "      </credential-store>\n" +
+        "    </service>\n" +
+        "  </services>\n" +
+        "</metainfo>\n";
     serviceInfoMap = getServiceInfo(serviceInfoXml);
     service = serviceInfoMap.get("HBASE");
     assertTrue(service.isCredentialStoreSupported());
@@ -234,21 +236,20 @@ public class ServiceInfoTest {
   }
 
   @Test
-  public void testCredentialStoreInfoValidity() throws Exception
-  {
+  public void testCredentialStoreInfoValidity() throws Exception {
     // Valid: Supported->True, Enabled->False
     String serviceInfoXml = "<metainfo>\n" +
-            "  <schemaVersion>2.0</schemaVersion>\n" +
-            "  <services>\n" +
-            "    <service>\n" +
-            "      <name>RANGER</name>\n" +
-            "      <credential-store>\n" +
-            "          <supported>true</supported>\n" +
-            "          <enabled>false</enabled>\n" +
-            "      </credential-store>\n" +
-            "    </service>\n" +
-            "  </services>\n" +
-            "</metainfo>\n";
+        "  <schemaVersion>2.0</schemaVersion>\n" +
+        "  <services>\n" +
+        "    <service>\n" +
+        "      <name>RANGER</name>\n" +
+        "      <credential-store>\n" +
+        "          <supported>true</supported>\n" +
+        "          <enabled>false</enabled>\n" +
+        "      </credential-store>\n" +
+        "    </service>\n" +
+        "  </services>\n" +
+        "</metainfo>\n";
 
     Map<String, ServiceInfo> serviceInfoMap = getServiceInfo(serviceInfoXml);
     ServiceInfo serviceInfo = serviceInfoMap.get("RANGER");
@@ -256,17 +257,17 @@ public class ServiceInfoTest {
 
     // Valid: Supported->True, Enabled->True
     serviceInfoXml = "<metainfo>\n" +
-            "  <schemaVersion>2.0</schemaVersion>\n" +
-            "  <services>\n" +
-            "    <service>\n" +
-            "      <name>RANGER</name>\n" +
-            "      <credential-store>\n" +
-            "          <supported>true</supported>\n" +
-            "          <enabled>true</enabled>\n" +
-            "      </credential-store>\n" +
-            "    </service>\n" +
-            "  </services>\n" +
-            "</metainfo>\n";
+        "  <schemaVersion>2.0</schemaVersion>\n" +
+        "  <services>\n" +
+        "    <service>\n" +
+        "      <name>RANGER</name>\n" +
+        "      <credential-store>\n" +
+        "          <supported>true</supported>\n" +
+        "          <enabled>true</enabled>\n" +
+        "      </credential-store>\n" +
+        "    </service>\n" +
+        "  </services>\n" +
+        "</metainfo>\n";
 
     serviceInfoMap = getServiceInfo(serviceInfoXml);
     serviceInfo = serviceInfoMap.get("RANGER");
@@ -274,17 +275,17 @@ public class ServiceInfoTest {
 
     // Valid: Supported->False, Enabled->False
     serviceInfoXml = "<metainfo>\n" +
-            "  <schemaVersion>2.0</schemaVersion>\n" +
-            "  <services>\n" +
-            "    <service>\n" +
-            "      <name>RANGER</name>\n" +
-            "      <credential-store>\n" +
-            "          <supported>false</supported>\n" +
-            "          <enabled>false</enabled>\n" +
-            "      </credential-store>\n" +
-            "    </service>\n" +
-            "  </services>\n" +
-            "</metainfo>\n";
+        "  <schemaVersion>2.0</schemaVersion>\n" +
+        "  <services>\n" +
+        "    <service>\n" +
+        "      <name>RANGER</name>\n" +
+        "      <credential-store>\n" +
+        "          <supported>false</supported>\n" +
+        "          <enabled>false</enabled>\n" +
+        "      </credential-store>\n" +
+        "    </service>\n" +
+        "  </services>\n" +
+        "</metainfo>\n";
 
     serviceInfoMap = getServiceInfo(serviceInfoXml);
     serviceInfo = serviceInfoMap.get("RANGER");
@@ -292,13 +293,13 @@ public class ServiceInfoTest {
 
     // Valid: credential-store not specified
     serviceInfoXml = "<metainfo>\n" +
-            "  <schemaVersion>2.0</schemaVersion>\n" +
-            "  <services>\n" +
-            "    <service>\n" +
-            "      <name>RANGER</name>\n" +
-            "    </service>\n" +
-            "  </services>\n" +
-            "</metainfo>\n";
+        "  <schemaVersion>2.0</schemaVersion>\n" +
+        "  <services>\n" +
+        "    <service>\n" +
+        "      <name>RANGER</name>\n" +
+        "    </service>\n" +
+        "  </services>\n" +
+        "</metainfo>\n";
 
     serviceInfoMap = getServiceInfo(serviceInfoXml);
     serviceInfo = serviceInfoMap.get("RANGER");
@@ -307,17 +308,17 @@ public class ServiceInfoTest {
     // Specified but invalid
     // Invalid: Supported->False, Enabled->True
     serviceInfoXml = "<metainfo>\n" +
-            "  <schemaVersion>2.0</schemaVersion>\n" +
-            "  <services>\n" +
-            "    <service>\n" +
-            "      <name>RANGER</name>\n" +
-            "      <credential-store>\n" +
-            "          <supported>false</supported>\n" +
-            "          <enabled>true</enabled>\n" +
-            "      </credential-store>\n" +
-            "    </service>\n" +
-            "  </services>\n" +
-            "</metainfo>\n";
+        "  <schemaVersion>2.0</schemaVersion>\n" +
+        "  <services>\n" +
+        "    <service>\n" +
+        "      <name>RANGER</name>\n" +
+        "      <credential-store>\n" +
+        "          <supported>false</supported>\n" +
+        "          <enabled>true</enabled>\n" +
+        "      </credential-store>\n" +
+        "    </service>\n" +
+        "  </services>\n" +
+        "</metainfo>\n";
 
     serviceInfoMap = getServiceInfo(serviceInfoXml);
     serviceInfo = serviceInfoMap.get("RANGER");
@@ -325,15 +326,15 @@ public class ServiceInfoTest {
 
     // Invalid: Supported->Unspecified, Enabled->Unspecified
     serviceInfoXml = "<metainfo>\n" +
-            "  <schemaVersion>2.0</schemaVersion>\n" +
-            "  <services>\n" +
-            "    <service>\n" +
-            "      <name>RANGER</name>\n" +
-            "      <credential-store>\n" +
-            "      </credential-store>\n" +
-            "    </service>\n" +
-            "  </services>\n" +
-            "</metainfo>\n";
+        "  <schemaVersion>2.0</schemaVersion>\n" +
+        "  <services>\n" +
+        "    <service>\n" +
+        "      <name>RANGER</name>\n" +
+        "      <credential-store>\n" +
+        "      </credential-store>\n" +
+        "    </service>\n" +
+        "  </services>\n" +
+        "</metainfo>\n";
 
     serviceInfoMap = getServiceInfo(serviceInfoXml);
     serviceInfo = serviceInfoMap.get("RANGER");
@@ -341,16 +342,16 @@ public class ServiceInfoTest {
 
     // Invalid: Supported->Specified, Enabled->Unspecified
     serviceInfoXml = "<metainfo>\n" +
-            "  <schemaVersion>2.0</schemaVersion>\n" +
-            "  <services>\n" +
-            "    <service>\n" +
-            "      <name>RANGER</name>\n" +
-            "      <credential-store>\n" +
-            "          <supported>true</supported>\n" +
-            "      </credential-store>\n" +
-            "    </service>\n" +
-            "  </services>\n" +
-            "</metainfo>\n";
+        "  <schemaVersion>2.0</schemaVersion>\n" +
+        "  <services>\n" +
+        "    <service>\n" +
+        "      <name>RANGER</name>\n" +
+        "      <credential-store>\n" +
+        "          <supported>true</supported>\n" +
+        "      </credential-store>\n" +
+        "    </service>\n" +
+        "  </services>\n" +
+        "</metainfo>\n";
 
     serviceInfoMap = getServiceInfo(serviceInfoXml);
     serviceInfo = serviceInfoMap.get("RANGER");
@@ -358,16 +359,16 @@ public class ServiceInfoTest {
 
     // Invalid: Supported->Unspecified, Enabled->Specified
     serviceInfoXml = "<metainfo>\n" +
-            "  <schemaVersion>2.0</schemaVersion>\n" +
-            "  <services>\n" +
-            "    <service>\n" +
-            "      <name>RANGER</name>\n" +
-            "      <credential-store>\n" +
-            "          <enabled>true</enabled>\n" +
-            "      </credential-store>\n" +
-            "    </service>\n" +
-            "  </services>\n" +
-            "</metainfo>\n";
+        "  <schemaVersion>2.0</schemaVersion>\n" +
+        "  <services>\n" +
+        "    <service>\n" +
+        "      <name>RANGER</name>\n" +
+        "      <credential-store>\n" +
+        "          <enabled>true</enabled>\n" +
+        "      </credential-store>\n" +
+        "    </service>\n" +
+        "  </services>\n" +
+        "</metainfo>\n";
 
     serviceInfoMap = getServiceInfo(serviceInfoXml);
     serviceInfo = serviceInfoMap.get("RANGER");
@@ -388,25 +389,25 @@ public class ServiceInfoTest {
   @Test
   public void testServiceProperties() throws Exception {
     String serviceInfoXml =
-      "<metainfo>" +
-      "  <schemaVersion>2.0</schemaVersion>" +
-      "  <services>" +
-      "    <service>" +
-      "      <name>WITH_PROPS</name>" +
-      "      <displayName>WITH_PROPS</displayName>" +
-      "      <properties>" +
-      "        <property>" +
-      "          <name>PROP1</name>" +
-      "          <value>VAL1</value>" +
-      "        </property>" +
-      "        <property>" +
-      "          <name>PROP2</name>" +
-      "          <value>VAL2</value>" +
-      "        </property>" +
-      "      </properties>" +
-      "    </service>" +
-      "  </services>" +
-      "</metainfo>";
+        "<metainfo>" +
+            "  <schemaVersion>2.0</schemaVersion>" +
+            "  <services>" +
+            "    <service>" +
+            "      <name>WITH_PROPS</name>" +
+            "      <displayName>WITH_PROPS</displayName>" +
+            "      <properties>" +
+            "        <property>" +
+            "          <name>PROP1</name>" +
+            "          <value>VAL1</value>" +
+            "        </property>" +
+            "        <property>" +
+            "          <name>PROP2</name>" +
+            "          <value>VAL2</value>" +
+            "        </property>" +
+            "      </properties>" +
+            "    </service>" +
+            "  </services>" +
+            "</metainfo>";
 
     Map<String, ServiceInfo> serviceInfoMap = getServiceInfo(serviceInfoXml);
 
@@ -425,25 +426,25 @@ public class ServiceInfoTest {
   public void testDefaultVisibilityServiceProperties() throws Exception {
     // Given
     String serviceInfoXml =
-      "<metainfo>" +
-        "  <schemaVersion>2.0</schemaVersion>" +
-        "  <services>" +
-        "    <service>" +
-        "      <name>WITH_PROPS</name>" +
-        "      <displayName>WITH_PROPS</displayName>" +
-        "      <properties>" +
-        "        <property>" +
-        "          <name>PROP1</name>" +
-        "          <value>VAL1</value>" +
-        "        </property>" +
-        "        <property>" +
-        "          <name>PROP2</name>" +
-        "          <value>VAL2</value>" +
-        "        </property>" +
-        "      </properties>" +
-        "    </service>" +
-        "  </services>" +
-        "</metainfo>";
+        "<metainfo>" +
+            "  <schemaVersion>2.0</schemaVersion>" +
+            "  <services>" +
+            "    <service>" +
+            "      <name>WITH_PROPS</name>" +
+            "      <displayName>WITH_PROPS</displayName>" +
+            "      <properties>" +
+            "        <property>" +
+            "          <name>PROP1</name>" +
+            "          <value>VAL1</value>" +
+            "        </property>" +
+            "        <property>" +
+            "          <name>PROP2</name>" +
+            "          <value>VAL2</value>" +
+            "        </property>" +
+            "      </properties>" +
+            "    </service>" +
+            "  </services>" +
+            "</metainfo>";
 
     // When
     Map<String, ServiceInfo> serviceInfoMap = getServiceInfo(serviceInfoXml);
@@ -461,29 +462,29 @@ public class ServiceInfoTest {
   public void testVisibilityServicePropertyOverride() throws Exception {
     // Given
     String serviceInfoXml =
-      "<metainfo>" +
-        "  <schemaVersion>2.0</schemaVersion>" +
-        "  <services>" +
-        "    <service>" +
-        "      <name>WITH_PROPS</name>" +
-        "      <displayName>WITH_PROPS</displayName>" +
-        "      <properties>" +
-        "        <property>" +
-        "          <name>PROP1</name>" +
-        "          <value>VAL1</value>" +
-        "        </property>" +
-        "        <property>" +
-        "          <name>PROP2</name>" +
-        "          <value>VAL2</value>" +
-        "        </property>" +
-        "        <property>" +
-        "          <name>managed</name>" +
-        "          <value>false</value>" +
-        "        </property>" +
-        "      </properties>" +
-        "    </service>" +
-        "  </services>" +
-        "</metainfo>";
+        "<metainfo>" +
+            "  <schemaVersion>2.0</schemaVersion>" +
+            "  <services>" +
+            "    <service>" +
+            "      <name>WITH_PROPS</name>" +
+            "      <displayName>WITH_PROPS</displayName>" +
+            "      <properties>" +
+            "        <property>" +
+            "          <name>PROP1</name>" +
+            "          <value>VAL1</value>" +
+            "        </property>" +
+            "        <property>" +
+            "          <name>PROP2</name>" +
+            "          <value>VAL2</value>" +
+            "        </property>" +
+            "        <property>" +
+            "          <name>managed</name>" +
+            "          <value>false</value>" +
+            "        </property>" +
+            "      </properties>" +
+            "    </service>" +
+            "  </services>" +
+            "</metainfo>";
 
     // When
     Map<String, ServiceInfo> serviceInfoMap = getServiceInfo(serviceInfoXml);
@@ -499,34 +500,33 @@ public class ServiceInfoTest {
   }
 
   @Test
-  public void testDuplicateServicePropertyValidationAfterXmlDeserialization() 
throws Exception
-  {
+  public void testDuplicateServicePropertyValidationAfterXmlDeserialization() 
throws Exception {
     // Given
     String serviceInfoXml =
-      "<metainfo>" +
-        "  <schemaVersion>2.0</schemaVersion>" +
-        "  <services>" +
-        "    <service>" +
-        "      <version>1.0</version>" +
-        "      <name>WITH_DUPLICATE_PROPS</name>" +
-        "      <displayName>WITH_PROPS</displayName>" +
-        "      <properties>" +
-        "        <property>" +
-        "          <name>PROP1</name>" +
-        "          <value>VAL1</value>" +
-        "        </property>" +
-        "        <property>" +
-        "          <name>PROP1</name>" +
-        "          <value>VAL2</value>" +
-        "        </property>" +
-        "        <property>" +
-        "          <name>managed</name>" +
-        "          <value>false</value>" +
-        "        </property>" +
-        "      </properties>" +
-        "    </service>" +
-        "  </services>" +
-        "</metainfo>";
+        "<metainfo>" +
+            "  <schemaVersion>2.0</schemaVersion>" +
+            "  <services>" +
+            "    <service>" +
+            "      <version>1.0</version>" +
+            "      <name>WITH_DUPLICATE_PROPS</name>" +
+            "      <displayName>WITH_PROPS</displayName>" +
+            "      <properties>" +
+            "        <property>" +
+            "          <name>PROP1</name>" +
+            "          <value>VAL1</value>" +
+            "        </property>" +
+            "        <property>" +
+            "          <name>PROP1</name>" +
+            "          <value>VAL2</value>" +
+            "        </property>" +
+            "        <property>" +
+            "          <name>managed</name>" +
+            "          <value>false</value>" +
+            "        </property>" +
+            "      </properties>" +
+            "    </service>" +
+            "  </services>" +
+            "</metainfo>";
 
     // When
     Map<String, ServiceInfo> serviceInfoMap = getServiceInfo(serviceInfoXml);
@@ -566,45 +566,44 @@ public class ServiceInfoTest {
 
 
   @Test
-  public void testMultiplePimaryLogsValidationAfterXmlDeserialization() throws 
Exception
-  {
+  public void testMultiplePimaryLogsValidationAfterXmlDeserialization() throws 
Exception {
     // Given
     String serviceInfoXml =
         "<metainfo>" +
-        "  <schemaVersion>2.0</schemaVersion>" +
-        "  <services>" +
-        "    <service>" +
-        "      <version>1.0</version>" +
-        "      <name>WITH_MULTIPLE_PRIMARY_LOGS</name>" +
-        "      <displayName>WITH_MULTIPLE_PRIMARY_LOGS</displayName>" +
-        "      <properties>" +
-        "        <property>" +
-        "          <name>managed</name>" +
-        "          <value>false</value>" +
-        "        </property>" +
-        "      </properties>" +
-        "      <components> " +
-        "        <component> " +
-        "          <name>COMPONENT_WITH_MULTIPLE_PRIMARY_LOG</name> " +
-        "          
<displayName>COMPONENT_WITH_MULTIPLE_PRIMARY_LOG</displayName> " +
-        "          <category>MASTER</category> " +
-        "          <cardinality>0-1</cardinality> " +
-        "          <versionAdvertised>true</versionAdvertised> " +
-        "          <logs> " +
-        "            <log> " +
-        "              <logId>log1</logId> " +
-        "              <primary>true</primary> " +
-        "            </log> " +
-        "            <log> " +
-        "              <logId>log2</logId> " +
-        "              <primary>true</primary> " +
-        "            </log> " +
-        "          </logs> " +
-        "       </component> " +
-        "      </components> " +
-        "    </service>" +
-        "  </services>" +
-        "</metainfo>";
+            "  <schemaVersion>2.0</schemaVersion>" +
+            "  <services>" +
+            "    <service>" +
+            "      <version>1.0</version>" +
+            "      <name>WITH_MULTIPLE_PRIMARY_LOGS</name>" +
+            "      <displayName>WITH_MULTIPLE_PRIMARY_LOGS</displayName>" +
+            "      <properties>" +
+            "        <property>" +
+            "          <name>managed</name>" +
+            "          <value>false</value>" +
+            "        </property>" +
+            "      </properties>" +
+            "      <components> " +
+            "        <component> " +
+            "          <name>COMPONENT_WITH_MULTIPLE_PRIMARY_LOG</name> " +
+            "          
<displayName>COMPONENT_WITH_MULTIPLE_PRIMARY_LOG</displayName> " +
+            "          <category>MASTER</category> " +
+            "          <cardinality>0-1</cardinality> " +
+            "          <versionAdvertised>true</versionAdvertised> " +
+            "          <logs> " +
+            "            <log> " +
+            "              <logId>log1</logId> " +
+            "              <primary>true</primary> " +
+            "            </log> " +
+            "            <log> " +
+            "              <logId>log2</logId> " +
+            "              <primary>true</primary> " +
+            "            </log> " +
+            "          </logs> " +
+            "       </component> " +
+            "      </components> " +
+            "    </service>" +
+            "  </services>" +
+            "</metainfo>";
 
     // When
     Map<String, ServiceInfo> serviceInfoMap = getServiceInfo(serviceInfoXml);
@@ -655,50 +654,141 @@ public class ServiceInfoTest {
   public void testSupportDeleteViaUI() throws Exception {
     //Explicitly set to true
     String serviceInfoXml =
-      "<metainfo>" +
-      "  <schemaVersion>2.0</schemaVersion>" +
-      "  <services>" +
-      "    <service>" +
-      "      <name>HDFS</name>" +
-      "      <displayName>HDFS</displayName>" +
-      "      <supportDeleteViaUI>true</supportDeleteViaUI>" +
-      "    </service>" +
-      "  </services>" +
-      "</metainfo>";
+        "<metainfo>" +
+            "  <schemaVersion>2.0</schemaVersion>" +
+            "  <services>" +
+            "    <service>" +
+            "      <name>HDFS</name>" +
+            "      <displayName>HDFS</displayName>" +
+            "      <supportDeleteViaUI>true</supportDeleteViaUI>" +
+            "    </service>" +
+            "  </services>" +
+            "</metainfo>";
     Map<String, ServiceInfo> serviceInfoMap = getServiceInfo(serviceInfoXml);
     assertTrue(serviceInfoMap.get("HDFS").isSupportDeleteViaUI());
 
     //Explicitly set to false
     serviceInfoXml =
         "<metainfo>" +
-        "  <schemaVersion>2.0</schemaVersion>" +
-        "  <services>" +
-        "    <service>" +
-        "      <name>HDFS</name>" +
-        "      <displayName>HDFS</displayName>" +
-        "      <supportDeleteViaUI>false</supportDeleteViaUI>" +
-        "    </service>" +
-        "  </services>" +
-        "</metainfo>";
-      serviceInfoMap = getServiceInfo(serviceInfoXml);
-      assertFalse(serviceInfoMap.get("HDFS").isSupportDeleteViaUI());
-
-      //Default to true
-      serviceInfoXml =
-          "<metainfo>" +
-          "  <schemaVersion>2.0</schemaVersion>" +
-          "  <services>" +
-          "    <service>" +
-          "      <name>HDFS</name>" +
-          "      <displayName>HDFS</displayName>" +
-          "    </service>" +
-          "  </services>" +
-          "</metainfo>";
-        serviceInfoMap = getServiceInfo(serviceInfoXml);
-        assertTrue(serviceInfoMap.get("HDFS").isSupportDeleteViaUI());
+            "  <schemaVersion>2.0</schemaVersion>" +
+            "  <services>" +
+            "    <service>" +
+            "      <name>HDFS</name>" +
+            "      <displayName>HDFS</displayName>" +
+            "      <supportDeleteViaUI>false</supportDeleteViaUI>" +
+            "    </service>" +
+            "  </services>" +
+            "</metainfo>";
+    serviceInfoMap = getServiceInfo(serviceInfoXml);
+    assertFalse(serviceInfoMap.get("HDFS").isSupportDeleteViaUI());
+
+    //Default to true
+    serviceInfoXml =
+        "<metainfo>" +
+            "  <schemaVersion>2.0</schemaVersion>" +
+            "  <services>" +
+            "    <service>" +
+            "      <name>HDFS</name>" +
+            "      <displayName>HDFS</displayName>" +
+            "    </service>" +
+            "  </services>" +
+            "</metainfo>";
+    serviceInfoMap = getServiceInfo(serviceInfoXml);
+    assertTrue(serviceInfoMap.get("HDFS").isSupportDeleteViaUI());
+  }
+
+  @Test
+  public void testSingleSignOnSupport() throws JAXBException {
+    // 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").isSingleSignOnSupported());
+    assertTrue(serviceInfoMap.get("SERVICE").isValid());
+
+    SingleSignOnInfo singleSignOnInfo = 
serviceInfoMap.get("SERVICE").getSingleSignOnInfo();
+    assertNull(singleSignOnInfo);
+
+    // Explicit SSO setting (true)
+    serviceInfoXml =
+        "<metainfo>" +
+            "  <schemaVersion>2.0</schemaVersion>" +
+            "  <services>" +
+            "    <service>" +
+            "      <name>SERVICE</name>" +
+            "      <sso>" +
+            "        <supported>true</supported>" +
+            "        
<enabledConfiguration>config-type/property_name</enabledConfiguration>" +
+            "      </sso>" +
+            "    </service>" +
+            "  </services>" +
+            "</metainfo>";
+    serviceInfoMap = getServiceInfo(serviceInfoXml);
+    assertTrue(serviceInfoMap.get("SERVICE").isSingleSignOnSupported());
+    assertTrue(serviceInfoMap.get("SERVICE").isValid());
+
+    singleSignOnInfo = serviceInfoMap.get("SERVICE").getSingleSignOnInfo();
+    assertNotNull(singleSignOnInfo);
+    assertTrue(singleSignOnInfo.isSupported());
+    assertEquals(Boolean.TRUE, singleSignOnInfo.getSupported());
+    assertEquals("config-type/property_name", 
singleSignOnInfo.getEnabledConfiguration());
+
+    // Explicit SSO setting (false)
+    serviceInfoXml =
+        "<metainfo>" +
+            "  <schemaVersion>2.0</schemaVersion>" +
+            "  <services>" +
+            "    <service>" +
+            "      <name>SERVICE</name>" +
+            "      <sso>" +
+            "        <supported>false</supported>" +
+            "      </sso>" +
+            "    </service>" +
+            "  </services>" +
+            "</metainfo>";
+    serviceInfoMap = getServiceInfo(serviceInfoXml);
+    assertFalse(serviceInfoMap.get("SERVICE").isSingleSignOnSupported());
+    assertTrue(serviceInfoMap.get("SERVICE").isValid());
+
+    singleSignOnInfo = serviceInfoMap.get("SERVICE").getSingleSignOnInfo();
+    assertNotNull(singleSignOnInfo);
+    assertFalse(singleSignOnInfo.isSupported());
+    assertEquals(Boolean.FALSE, singleSignOnInfo.getSupported());
+    assertNull(singleSignOnInfo.getEnabledConfiguration());
+
+    // Explicit SSO setting (invalid)
+    serviceInfoXml =
+        "<metainfo>" +
+            "  <schemaVersion>2.0</schemaVersion>" +
+            "  <services>" +
+            "    <service>" +
+            "      <name>SERVICE</name>" +
+            "      <sso>" +
+            "        <supported>true</supported>" +
+            "      </sso>" +
+            "    </service>" +
+            "  </services>" +
+            "</metainfo>";
+    serviceInfoMap = getServiceInfo(serviceInfoXml);
+    assertTrue(serviceInfoMap.get("SERVICE").isSingleSignOnSupported());
+    assertFalse(serviceInfoMap.get("SERVICE").isValid());
+    assertEquals(1, serviceInfoMap.get("SERVICE").getErrors().size());
+
+    singleSignOnInfo = serviceInfoMap.get("SERVICE").getSingleSignOnInfo();
+    assertNotNull(singleSignOnInfo);
+    assertTrue(singleSignOnInfo.isSupported());
+    assertEquals(Boolean.TRUE, singleSignOnInfo.getSupported());
+    assertNull(singleSignOnInfo.getEnabledConfiguration());
   }
 
-  public static Map<String, ServiceInfo> getServiceInfo(String xml) throws 
JAXBException {
+  private static Map<String, ServiceInfo> getServiceInfo(String xml) throws 
JAXBException {
     InputStream configStream = new ByteArrayInputStream(xml.getBytes());
     JAXBContext jaxbContext = 
JAXBContext.newInstance(ServiceMetainfoXml.class);
     Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();

-- 
To stop receiving notification emails like this one, please contact
[email protected].

Reply via email to