You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by lp...@apache.org on 2017/10/30 15:20:25 UTC

[3/4] ambari git commit: AMBARI-21307 Feature for supporting LDAP configuration from the UI

http://git-wip-us.apache.org/repos/asf/ambari/blob/6b7a7a70/ambari-server/src/main/java/org/apache/ambari/server/ldap/LdapModule.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/ldap/LdapModule.java b/ambari-server/src/main/java/org/apache/ambari/server/ldap/LdapModule.java
new file mode 100644
index 0000000..089da1d
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/ldap/LdapModule.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed 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.ldap;
+
+import org.apache.ambari.server.ldap.domain.AmbariLdapConfiguration;
+import org.apache.ambari.server.ldap.domain.AmbariLdapConfigurationFactory;
+import org.apache.ambari.server.ldap.service.AmbariLdapConfigurationProvider;
+import org.apache.ambari.server.ldap.service.AmbariLdapFacade;
+import org.apache.ambari.server.ldap.service.AttributeDetector;
+import org.apache.ambari.server.ldap.service.LdapAttributeDetectionService;
+import org.apache.ambari.server.ldap.service.LdapConfigurationService;
+import org.apache.ambari.server.ldap.service.LdapConnectionConfigService;
+import org.apache.ambari.server.ldap.service.LdapFacade;
+import org.apache.ambari.server.ldap.service.ads.DefaultLdapAttributeDetectionService;
+import org.apache.ambari.server.ldap.service.ads.DefaultLdapConfigurationService;
+import org.apache.ambari.server.ldap.service.ads.DefaultLdapConnectionConfigService;
+import org.apache.ambari.server.ldap.service.ads.detectors.AttributeDetectorFactory;
+import org.apache.ambari.server.ldap.service.ads.detectors.GroupMemberAttrDetector;
+import org.apache.ambari.server.ldap.service.ads.detectors.GroupNameAttrDetector;
+import org.apache.ambari.server.ldap.service.ads.detectors.GroupObjectClassDetector;
+import org.apache.ambari.server.ldap.service.ads.detectors.UserGroupMemberAttrDetector;
+import org.apache.ambari.server.ldap.service.ads.detectors.UserNameAttrDetector;
+import org.apache.ambari.server.ldap.service.ads.detectors.UserObjectClassDetector;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.assistedinject.FactoryModuleBuilder;
+import com.google.inject.multibindings.Multibinder;
+import com.google.inject.name.Names;
+
+/**
+ * GUICE configuration module for setting up LDAP related infrastructure.
+ */
+public class LdapModule extends AbstractModule {
+
+  public static final String USER_ATTRIBUTES_DETECTORS = "UserAttributesDetectors";
+  public static final String GROUP_ATTRIBUTES_DETECTORS = "GroupAttributesDetectors";
+
+  @Override
+  protected void configure() {
+    bind(LdapFacade.class).to(AmbariLdapFacade.class);
+    bind(LdapConfigurationService.class).to(DefaultLdapConfigurationService.class);
+    bind(LdapAttributeDetectionService.class).to(DefaultLdapAttributeDetectionService.class);
+    bind(LdapConnectionConfigService.class).to(DefaultLdapConnectionConfigService.class);
+
+    // this binding requires the JPA module!
+    bind(AmbariLdapConfiguration.class).toProvider(AmbariLdapConfigurationProvider.class);
+
+    bind(AttributeDetectorFactory.class);
+
+    install(new FactoryModuleBuilder().build(AmbariLdapConfigurationFactory.class));
+
+    // binding the set of user attributes detector
+    Multibinder<AttributeDetector> userAttributeDetectorBinder = Multibinder.newSetBinder(binder(), AttributeDetector.class,
+      Names.named(USER_ATTRIBUTES_DETECTORS));
+    userAttributeDetectorBinder.addBinding().to(UserObjectClassDetector.class);
+    userAttributeDetectorBinder.addBinding().to(UserNameAttrDetector.class);
+    userAttributeDetectorBinder.addBinding().to(UserGroupMemberAttrDetector.class);
+
+
+    // binding the set of group attributes detector
+    Multibinder<AttributeDetector> groupAttributeDetectorBinder = Multibinder.newSetBinder(binder(), AttributeDetector.class,
+      Names.named(GROUP_ATTRIBUTES_DETECTORS));
+    groupAttributeDetectorBinder.addBinding().to(GroupObjectClassDetector.class);
+    groupAttributeDetectorBinder.addBinding().to(GroupNameAttrDetector.class);
+    groupAttributeDetectorBinder.addBinding().to(GroupMemberAttrDetector.class);
+
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/6b7a7a70/ambari-server/src/main/java/org/apache/ambari/server/ldap/domain/AmbariLdapConfigKeys.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/ldap/domain/AmbariLdapConfigKeys.java b/ambari-server/src/main/java/org/apache/ambari/server/ldap/domain/AmbariLdapConfigKeys.java
new file mode 100644
index 0000000..da655ad
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/ldap/domain/AmbariLdapConfigKeys.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed 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.ldap.domain;
+
+/**
+ * Constants representing supported LDAP related property names
+ * // todo extend this with validation information, description, defaults maybe
+ */
+public enum AmbariLdapConfigKeys {
+
+  LDAP_ENABLED("ambari.ldap.authentication.enabled"),
+  SERVER_HOST("ambari.ldap.connectivity.server.host"),
+  SERVER_PORT("ambari.ldap.connectivity.server.port"),
+  USE_SSL("ambari.ldap.connectivity.use_ssl"),
+
+  TRUST_STORE("ambari.ldap.connectivity.trust_store"),
+  TRUST_STORE_TYPE("ambari.ldap.connectivity.trust_store.type"),
+  TRUST_STORE_PATH("ambari.ldap.connectivity.trust_store.path"),
+  TRUST_STORE_PASSWORD("ambari.ldap.connectivity.trust_store.password"),
+  ANONYMOUS_BIND("ambari.ldap.connectivity.anonymous_bind"),
+
+  BIND_DN("ambari.ldap.connectivity.bind_dn"),
+  BIND_PASSWORD("ambari.ldap.connectivity.bind_password"),
+
+  ATTR_DETECTION("ambari.ldap.attributes.detection"), // manual | auto
+
+  DN_ATTRIBUTE("ambari.ldap.attributes.dn_attr"),
+
+  USER_OBJECT_CLASS("ambari.ldap.attributes.user.object_class"),
+  USER_NAME_ATTRIBUTE("ambari.ldap.attributes.user.name_attr"),
+  USER_GROUP_MEMBER_ATTRIBUTE("ambari.ldap.attributes.user.group_member_attr"),
+  USER_SEARCH_BASE("ambari.ldap.attributes.user.search_base"),
+
+  GROUP_OBJECT_CLASS("ambari.ldap.attributes.group.object_class"),
+  GROUP_NAME_ATTRIBUTE("ambari.ldap.attributes.group.name_attr"),
+  GROUP_MEMBER_ATTRIBUTE("ambari.ldap.attributes.group.member_attr"),
+  GROUP_SEARCH_BASE("ambari.ldap.attributes.group.search_base"),
+
+  USER_SEARCH_FILTER("ambari.ldap.advanced.user_search_filter"),
+  USER_MEMBER_REPLACE_PATTERN("ambari.ldap.advanced.user_member_replace_pattern"),
+  USER_MEMBER_FILTER("ambari.ldap.advanced.user_member_filter"),
+
+  GROUP_SEARCH_FILTER("ambari.ldap.advanced.group_search_filter"),
+  GROUP_MEMBER_REPLACE_PATTERN("ambari.ldap.advanced.group_member_replace_pattern"),
+  GROUP_MEMBER_FILTER("ambari.ldap.advanced.group_member_filter"),
+
+  FORCE_LOWERCASE_USERNAMES("ambari.ldap.advanced.force_lowercase_usernames"),
+  REFERRAL_HANDLING("ambari.ldap.advanced.referrals"), // folow
+  PAGINATION_ENABLED("ambari.ldap.advanced.pagination_enabled"); // true | false
+
+  private String propertyName;
+
+  AmbariLdapConfigKeys(String propName) {
+    this.propertyName = propName;
+  }
+
+  public String key() {
+    return this.propertyName;
+  }
+
+  public static AmbariLdapConfigKeys fromKeyStr(String keyStr) {
+    for (AmbariLdapConfigKeys key : values()) {
+      if (key.key().equals(keyStr)) {
+        return key;
+      }
+    }
+
+    throw new IllegalStateException("invalid konfiguration key found!");
+
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/6b7a7a70/ambari-server/src/main/java/org/apache/ambari/server/ldap/domain/AmbariLdapConfiguration.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/ldap/domain/AmbariLdapConfiguration.java b/ambari-server/src/main/java/org/apache/ambari/server/ldap/domain/AmbariLdapConfiguration.java
new file mode 100644
index 0000000..8b26cd3
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/ldap/domain/AmbariLdapConfiguration.java
@@ -0,0 +1,199 @@
+/*
+ * Licensed 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.ldap.domain;
+
+import java.util.Map;
+
+import javax.inject.Inject;
+
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.inject.assistedinject.Assisted;
+
+/**
+ * This class is an immutable representation of all the LDAP related configurationMap entries.
+ */
+public class AmbariLdapConfiguration {
+
+  private static final Logger LOGGER = LoggerFactory.getLogger(AmbariLdapConfiguration.class);
+
+  private final Map<String, Object> configurationMap;
+
+  private Object configValue(AmbariLdapConfigKeys ambariLdapConfigKeys) {
+    Object value = null;
+    if (configurationMap.containsKey(ambariLdapConfigKeys.key())) {
+      value = configurationMap.get(ambariLdapConfigKeys.key());
+    } else {
+      LOGGER.warn("Ldap configuration property [{}] hasn't been set", ambariLdapConfigKeys.key());
+    }
+    return value;
+  }
+
+  public void setValueFor(AmbariLdapConfigKeys ambariLdapConfigKeys, Object value) {
+    configurationMap.put(ambariLdapConfigKeys.key(), value);
+  }
+
+  // intentionally package private, instances to be created through the factory
+  @Inject
+  AmbariLdapConfiguration(@Assisted Map<String, Object> configuration) {
+    this.configurationMap = configuration;
+  }
+
+  public boolean ldapEnabled() {
+    return Boolean.valueOf((String) configValue(AmbariLdapConfigKeys.LDAP_ENABLED));
+  }
+
+  public String serverHost() {
+    return (String) configValue(AmbariLdapConfigKeys.SERVER_HOST);
+  }
+
+  public int serverPort() {
+    return Integer.valueOf((String) configValue(AmbariLdapConfigKeys.SERVER_PORT));
+  }
+
+  public boolean useSSL() {
+    return Boolean.valueOf((String) configValue(AmbariLdapConfigKeys.USE_SSL));
+  }
+
+  public String trustStore() {
+    return (String) configValue(AmbariLdapConfigKeys.TRUST_STORE);
+  }
+
+  public String trustStoreType() {
+    return (String) configValue(AmbariLdapConfigKeys.TRUST_STORE_TYPE);
+  }
+
+  public String trustStorePath() {
+    return (String) configValue(AmbariLdapConfigKeys.TRUST_STORE_PATH);
+  }
+
+  public String trustStorePassword() {
+    return (String) configValue(AmbariLdapConfigKeys.TRUST_STORE_PASSWORD);
+  }
+
+  public boolean anonymousBind() {
+    return Boolean.valueOf((String) configValue(AmbariLdapConfigKeys.ANONYMOUS_BIND));
+  }
+
+  public String bindDn() {
+    return (String) configValue(AmbariLdapConfigKeys.BIND_DN);
+  }
+
+  public String bindPassword() {
+    return (String) configValue(AmbariLdapConfigKeys.BIND_PASSWORD);
+  }
+
+  public String attributeDetection() {
+    return (String) configValue(AmbariLdapConfigKeys.ATTR_DETECTION);
+  }
+
+  public String dnAttribute() {
+    return (String) configValue(AmbariLdapConfigKeys.DN_ATTRIBUTE);
+  }
+
+  public String userObjectClass() {
+    return (String) configValue(AmbariLdapConfigKeys.USER_OBJECT_CLASS);
+  }
+
+  public String userNameAttribute() {
+    return (String) configValue(AmbariLdapConfigKeys.USER_NAME_ATTRIBUTE);
+  }
+
+  public String userSearchBase() {
+    return (String) configValue(AmbariLdapConfigKeys.USER_SEARCH_BASE);
+  }
+
+  public String groupObjectClass() {
+    return (String) configValue(AmbariLdapConfigKeys.GROUP_OBJECT_CLASS);
+  }
+
+  public String groupNameAttribute() {
+    return (String) configValue(AmbariLdapConfigKeys.GROUP_NAME_ATTRIBUTE);
+  }
+
+  public String groupMemberAttribute() {
+    return (String) configValue(AmbariLdapConfigKeys.GROUP_MEMBER_ATTRIBUTE);
+  }
+
+  public String groupSearchBase() {
+    return (String) configValue(AmbariLdapConfigKeys.GROUP_SEARCH_BASE);
+  }
+
+  public String userSearchFilter() {
+    return (String) configValue(AmbariLdapConfigKeys.USER_SEARCH_FILTER);
+  }
+
+  public String userMemberReplacePattern() {
+    return (String) configValue(AmbariLdapConfigKeys.USER_MEMBER_REPLACE_PATTERN);
+  }
+
+  public String userMemberFilter() {
+    return (String) configValue(AmbariLdapConfigKeys.USER_MEMBER_FILTER);
+  }
+
+  public String groupSearchFilter() {
+    return (String) configValue(AmbariLdapConfigKeys.GROUP_SEARCH_FILTER);
+  }
+
+  public String groupMemberReplacePattern() {
+    return (String) configValue(AmbariLdapConfigKeys.GROUP_MEMBER_REPLACE_PATTERN);
+  }
+
+  public String groupMemberFilter() {
+    return (String) configValue(AmbariLdapConfigKeys.GROUP_MEMBER_FILTER);
+  }
+
+  public boolean forceLowerCaseUserNames() {
+    return Boolean.valueOf((String) configValue(AmbariLdapConfigKeys.FORCE_LOWERCASE_USERNAMES));
+  }
+
+  public boolean paginationEnabled() {
+    return Boolean.valueOf((String) configValue(AmbariLdapConfigKeys.PAGINATION_ENABLED));
+  }
+
+  public String referralHandling() {
+    return (String) configValue(AmbariLdapConfigKeys.REFERRAL_HANDLING);
+  }
+
+
+  @Override
+  public String toString() {
+    return configurationMap.toString();
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+
+    if (o == null || getClass() != o.getClass()) return false;
+
+    AmbariLdapConfiguration that = (AmbariLdapConfiguration) o;
+
+    return new EqualsBuilder()
+      .append(configurationMap, that.configurationMap)
+      .isEquals();
+  }
+
+  @Override
+  public int hashCode() {
+    return new HashCodeBuilder(17, 37)
+      .append(configurationMap)
+      .toHashCode();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/6b7a7a70/ambari-server/src/main/java/org/apache/ambari/server/ldap/domain/AmbariLdapConfigurationFactory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/ldap/domain/AmbariLdapConfigurationFactory.java b/ambari-server/src/main/java/org/apache/ambari/server/ldap/domain/AmbariLdapConfigurationFactory.java
new file mode 100644
index 0000000..2b9f24b
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/ldap/domain/AmbariLdapConfigurationFactory.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed 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.ldap.domain;
+
+import java.util.Map;
+
+/**
+ * Factory interface for AmbariLdapConfiguration instances.
+ * It's registered as a factory in the GUICE context (so no implementations required)
+ *
+ * To be extended with other factory methods upon needs.
+ */
+public interface AmbariLdapConfigurationFactory {
+
+  /**
+   * Creates an AmbariLdapConfiguration instance with the provided map of configuration settings.
+   *
+   * @param configuration a map where keys are the configuration properties and values are the configuration values
+   * @return an AmbariLdapConfiguration instance
+   */
+  AmbariLdapConfiguration createLdapConfiguration(Map<String, Object> configuration);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/6b7a7a70/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/AmbariLdapConfigurationProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/AmbariLdapConfigurationProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/AmbariLdapConfigurationProvider.java
new file mode 100644
index 0000000..c88d420
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/AmbariLdapConfigurationProvider.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed 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.ldap.service;
+
+import java.util.Map;
+import java.util.Set;
+
+import javax.inject.Inject;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+
+import org.apache.ambari.server.events.AmbariLdapConfigChangedEvent;
+import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
+import org.apache.ambari.server.ldap.domain.AmbariLdapConfiguration;
+import org.apache.ambari.server.ldap.domain.AmbariLdapConfigurationFactory;
+import org.apache.ambari.server.orm.dao.AmbariConfigurationDAO;
+import org.apache.ambari.server.orm.entities.AmbariConfigurationEntity;
+import org.apache.ambari.server.security.authorization.AmbariLdapAuthenticationProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.eventbus.Subscribe;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+/**
+ * Provider implementation for LDAP configurations.
+ * It needs to be registered in the related GUICE module as a provider.
+ * It's responsible for managing LDAP configurations in the application.
+ * Whenever requested, this provider returns an AmbariLdapConfiguration which is always in sync with the persisted LDAP
+ * configuration resource.
+ *
+ * The provider receives notifications on CRUD operations related to the persisted resource and reloads the cached
+ * configuration instance accordingly.
+ */
+@Singleton
+public class AmbariLdapConfigurationProvider implements Provider<AmbariLdapConfiguration> {
+
+  private static final Logger LOGGER = LoggerFactory.getLogger(AmbariLdapAuthenticationProvider.class);
+  private AmbariLdapConfiguration instance;
+
+  @Inject
+  private AmbariEventPublisher publisher;
+
+  @Inject
+  private Provider<AmbariConfigurationDAO> ambariConfigurationDAOProvider;
+
+  @Inject
+  private AmbariLdapConfigurationFactory ldapConfigurationFactory;
+
+  private Gson gson = new GsonBuilder().create();
+
+  @Inject
+  public AmbariLdapConfigurationProvider() {
+  }
+
+  @Inject
+  void register() {
+    publisher.register(this);
+  }
+
+  @Override
+  public AmbariLdapConfiguration get() {
+    return instance != null ? instance : loadInstance(null);
+  }
+
+  /**
+   * Loads the AmbariLdapConfiguration from the database.
+   *
+   * @param configurationId the configuration id
+   * @return the AmbariLdapConfiguration instance
+   */
+  private AmbariLdapConfiguration loadInstance(Long configurationId) {
+    AmbariConfigurationEntity configEntity = null;
+
+    LOGGER.info("Loading LDAP configuration ...");
+    if (null == configurationId) {
+
+      LOGGER.debug("Initial loading of the ldap configuration ...");
+      configEntity = ambariConfigurationDAOProvider.get().getLdapConfiguration();
+
+    } else {
+
+      LOGGER.debug("Reloading configuration based on the provied id: {}", configurationId);
+      configEntity = ambariConfigurationDAOProvider.get().findByPK(configurationId);
+
+    }
+
+    if (configEntity != null) {
+      Set propertyMaps = gson.fromJson(configEntity.getConfigurationBaseEntity().getConfigurationData(), Set.class);
+      instance = ldapConfigurationFactory.createLdapConfiguration((Map<String, Object>) propertyMaps.iterator().next());
+    }
+
+    LOGGER.info("Loaded LDAP configuration instance: [ {} ]", instance);
+
+    return instance;
+  }
+
+  // On changing the configuration, the provider gets updated with the fresh value
+  @Subscribe
+  public void ambariLdapConfigChanged(AmbariLdapConfigChangedEvent event) {
+    LOGGER.info("LDAP config changed event received: {}", event);
+    loadInstance(event.getConfigurationId());
+    LOGGER.info("Refreshed LDAP config instance.");
+  }
+
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/6b7a7a70/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/AmbariLdapException.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/AmbariLdapException.java b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/AmbariLdapException.java
new file mode 100644
index 0000000..cb38acc
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/AmbariLdapException.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed 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.ldap.service;
+
+public class AmbariLdapException extends Exception {
+  public AmbariLdapException() {
+    super();
+  }
+
+  public AmbariLdapException(String message) {
+    super(message);
+  }
+
+  public AmbariLdapException(String message, Throwable cause) {
+    super(message, cause);
+  }
+
+  public AmbariLdapException(Throwable cause) {
+    super(cause);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/6b7a7a70/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/AmbariLdapFacade.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/AmbariLdapFacade.java b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/AmbariLdapFacade.java
new file mode 100644
index 0000000..0118840
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/AmbariLdapFacade.java
@@ -0,0 +1,140 @@
+/*
+ * Licensed 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.ldap.service;
+
+import java.util.Map;
+import java.util.Set;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.apache.ambari.server.ldap.domain.AmbariLdapConfiguration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Singleton
+public class AmbariLdapFacade implements LdapFacade {
+
+  private static final Logger LOGGER = LoggerFactory.getLogger(AmbariLdapFacade.class);
+
+  /**
+   * Additional parameters expected to be provided along with the configuration
+   */
+  public enum Parameters {
+    TEST_USER_NAME("ambari.ldap.test.user.name"),
+    TEST_USER_PASSWORD("ambari.ldap.test.user.password");
+
+    private String parameterKey;
+
+    Parameters(String parameterKey) {
+      this.parameterKey = parameterKey;
+    }
+
+    public String getParameterKey() {
+      return parameterKey;
+    }
+
+  }
+
+  @Inject
+  private LdapConfigurationService ldapConfigurationService;
+
+  @Inject
+  private LdapAttributeDetectionService ldapAttributeDetectionService;
+
+  @Inject
+  public AmbariLdapFacade() {
+  }
+
+  @Override
+  public void checkConnection(AmbariLdapConfiguration ambariLdapConfiguration) throws AmbariLdapException {
+    try {
+
+      ldapConfigurationService.checkConnection(ambariLdapConfiguration);
+      LOGGER.info("Validating LDAP connection related configuration: SUCCESS");
+
+    } catch (Exception e) {
+
+      LOGGER.error("Validating LDAP connection configuration failed", e);
+      throw new AmbariLdapException(e);
+
+    }
+
+  }
+
+
+  @Override
+  public AmbariLdapConfiguration detectAttributes(AmbariLdapConfiguration ambariLdapConfiguration) throws AmbariLdapException {
+    LOGGER.info("Detecting LDAP configuration attributes ...");
+
+    try {
+      LOGGER.info("Detecting user attributes ....");
+      // decorate the configuration with detected user attributes
+      ambariLdapConfiguration = ldapAttributeDetectionService.detectLdapUserAttributes(ambariLdapConfiguration);
+
+      LOGGER.info("Detecting group attributes ....");
+      // decorate the configuration with detected group attributes
+      ambariLdapConfiguration = ldapAttributeDetectionService.detectLdapGroupAttributes(ambariLdapConfiguration);
+
+      LOGGER.info("Attribute detection finished.");
+      return ambariLdapConfiguration;
+
+    } catch (Exception e) {
+
+      LOGGER.error("Error during LDAP attribute detection", e);
+      throw new AmbariLdapException(e);
+
+    }
+  }
+
+  @Override
+  public Set<String> checkLdapAttributes(Map<String, Object> parameters, AmbariLdapConfiguration ldapConfiguration) throws AmbariLdapException {
+    String userName = getTestUserNameFromParameters(parameters);
+    String testUserPass = getTestUserPasswordFromParameters(parameters);
+
+    if (null == userName) {
+      throw new IllegalArgumentException("No test user available for testing LDAP attributes");
+    }
+
+    LOGGER.info("Testing LDAP user attributes with test user: {}", userName);
+    String userDn = ldapConfigurationService.checkUserAttributes(userName, testUserPass, ldapConfiguration);
+
+    // todo handle the case where group membership is stored in the user rather than the group
+    LOGGER.info("Testing LDAP group attributes with test user dn: {}", userDn);
+    Set<String> groups = ldapConfigurationService.checkGroupAttributes(userDn, ldapConfiguration);
+
+    return groups;
+  }
+
+
+  private String getTestUserNameFromParameters(Map<String, Object> parameters) {
+    return (String) parameterValue(parameters, Parameters.TEST_USER_NAME);
+  }
+
+  private String getTestUserPasswordFromParameters(Map<String, Object> parameters) {
+    return (String) parameterValue(parameters, Parameters.TEST_USER_PASSWORD);
+  }
+
+  private Object parameterValue(Map<String, Object> parameters, Parameters parameter) {
+    Object value = null;
+    if (parameters.containsKey(parameter.getParameterKey())) {
+      value = parameters.get(parameter.getParameterKey());
+    } else {
+      LOGGER.warn("Parameter [{}] is missing from parameters", parameter.getParameterKey());
+    }
+    return value;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/6b7a7a70/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/AttributeDetector.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/AttributeDetector.java b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/AttributeDetector.java
new file mode 100644
index 0000000..f39a1fd
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/AttributeDetector.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed 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.ldap.service;
+
+import java.util.Map;
+
+/**
+ * Operations for detecting LDAP related settings.
+ * The basis for the attribute or value detection is a set of entries returned by a search operation.
+ * Individual attribute detector implementations are responsible for detecting a specific set of attributes or values
+ */
+public interface AttributeDetector<T> {
+
+  /**
+   * Collects potential attribute names or values from a set of result entries.
+   *
+   * @param entry a result entry returned by a search operation
+   */
+  void collect(T entry);
+
+  /**
+   * Implements the decision based on which the "best" possible attribute or value is selected.
+   *
+   * @return a map of the form <property-key, detected-value>
+   */
+  Map<String, String> detect();
+
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/6b7a7a70/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/LdapAttributeDetectionService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/LdapAttributeDetectionService.java b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/LdapAttributeDetectionService.java
new file mode 100644
index 0000000..c08a2e0
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/LdapAttributeDetectionService.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed 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.ldap.service;
+
+import org.apache.ambari.server.ldap.domain.AmbariLdapConfiguration;
+
+/**
+ * Contract defining operations to detect user and group attributes.
+ */
+public interface LdapAttributeDetectionService {
+
+  /**
+   * Decorates the passed in configuration with the detected ldap user attribute values
+   *
+   * @param ambariLdapConfiguration configuration instance holding connection details
+   * @return the configuration decorated with user related attributes
+   */
+  AmbariLdapConfiguration detectLdapUserAttributes(AmbariLdapConfiguration ambariLdapConfiguration) throws AmbariLdapException;
+
+  /**
+   * Decorates the passed in configuration with the detected ldap group attribute values
+   *
+   * @param ambariLdapConfiguration configuration instance holding connection details
+   * @return the configuration decorated with group related attributes
+   */
+  AmbariLdapConfiguration detectLdapGroupAttributes(AmbariLdapConfiguration ambariLdapConfiguration) throws AmbariLdapException;
+}
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/6b7a7a70/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/LdapConfigurationService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/LdapConfigurationService.java b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/LdapConfigurationService.java
new file mode 100644
index 0000000..4b82aa2
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/LdapConfigurationService.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed 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.ldap.service;
+
+import java.util.Set;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.ldap.domain.AmbariLdapConfiguration;
+
+/**
+ * Collection of operations for validating ldap configuration.
+ * It's intended to decouple implementations using different libraries.
+ */
+public interface LdapConfigurationService {
+
+  /**
+   * Tests the connection based on the provided configuration.
+   *
+   * @param configuration the ambari ldap configuration instance
+   * @throws AmbariLdapException if the connection is not possible
+   */
+  void checkConnection(AmbariLdapConfiguration configuration) throws AmbariLdapException;
+
+
+  /**
+   * Implements LDAP user related configuration settings validation logic.
+   * Implementers communicate with the LDAP server (search, bind) to validate attributes in the provided configuration
+   * instance
+   *
+   * @param testUserName  the test username
+   * @param testPassword  the test password
+   * @param configuration the available ldap configuration
+   * @return The DN of the found user entry
+   * @throws AmbariException if the connection couldn't be estabilisheds
+   */
+  String checkUserAttributes(String testUserName, String testPassword, AmbariLdapConfiguration configuration) throws AmbariLdapException;
+
+  /**
+   * Checks whether the group related LDAP attributes in the configuration are correct.
+   *
+   * @param userDn
+   * @param ambariLdapConfiguration
+   * @return
+   * @throws AmbariLdapException
+   */
+  Set<String> checkGroupAttributes(String userDn, AmbariLdapConfiguration ambariLdapConfiguration) throws AmbariLdapException;
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/6b7a7a70/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/LdapConnectionConfigService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/LdapConnectionConfigService.java b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/LdapConnectionConfigService.java
new file mode 100644
index 0000000..a882075
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/LdapConnectionConfigService.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed 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.ldap.service;
+
+import org.apache.ambari.server.ldap.domain.AmbariLdapConfiguration;
+import org.apache.directory.ldap.client.api.LdapConnectionConfig;
+
+/**
+ * Contract for creating connection configuration instances.
+ * Implementers are in charge for implementing any required custom logic based on the ambari configuration properties.
+ * (Eg.: using custom key stores etc...)
+ */
+public interface LdapConnectionConfigService {
+
+  /**
+   * Creates and sets up an ldap connection configuration instance based on the provided ambari ldap configuration instance.
+   *
+   * @param ambariLdapConfiguration instance holding configuration values
+   * @return a set up ldap connection configuration instance
+   * @throws AmbariLdapException if an error occurs while setting up the connection configuration
+   */
+  LdapConnectionConfig createLdapConnectionConfig(AmbariLdapConfiguration ambariLdapConfiguration) throws AmbariLdapException;
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/6b7a7a70/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/LdapFacade.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/LdapFacade.java b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/LdapFacade.java
new file mode 100644
index 0000000..ef84d1b
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/LdapFacade.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed 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.ldap.service;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.ambari.server.ldap.domain.AmbariLdapConfiguration;
+
+/**
+ * The contract defining all the operations required by the application when communicating with an arbitrary LDAP server.
+ * This interface is intended to decouple LDAP specific details from the application.
+ *
+ * Any operation that requires interaction with an LDAP server from within Ambari should go through this interface.
+ * (LDAP)
+ */
+public interface LdapFacade {
+
+  /**
+   * Tests the connection to the LDAP server based on the provided configuration.
+   *
+   * @param ambariLdapConfiguration the available ldap related configuration
+   * @throws AmbariLdapException if the connection fails or other problems occur during the operation
+   */
+  void checkConnection(AmbariLdapConfiguration ambariLdapConfiguration) throws AmbariLdapException;
+
+
+  /**
+   * Runs the user and group attribute detection algorithms.
+   * The method is not intended to be used as a coniguration factory, the returned instance may not be suitable for use.
+   *
+   * @param ambariLdapConfiguration partially filled configuration instance to be extended with detected properties
+   * @return a configuration instance, with properties filled with potentially correct values
+   * @throws AmbariLdapException
+   */
+  AmbariLdapConfiguration detectAttributes(AmbariLdapConfiguration ambariLdapConfiguration) throws AmbariLdapException;
+
+  /**
+   * Checks user and group related LDAP configuration attributes in the configuration object with the help of the provided parameters
+   *
+   * @param parameters              a map of property name and value pairs holding information to facilitate checking the attributes
+   * @param ambariLdapConfiguration configutration instance with available attributes
+   * @throws AmbariLdapException if the attribute checking fails
+   */
+  Set<String> checkLdapAttributes(Map<String, Object> parameters, AmbariLdapConfiguration ambariLdapConfiguration) throws AmbariLdapException;
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/6b7a7a70/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/DefaultLdapAttributeDetectionService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/DefaultLdapAttributeDetectionService.java b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/DefaultLdapAttributeDetectionService.java
new file mode 100644
index 0000000..a9a9b53
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/DefaultLdapAttributeDetectionService.java
@@ -0,0 +1,200 @@
+/*
+ * Licensed 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.ldap.service.ads;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.apache.ambari.server.ldap.domain.AmbariLdapConfigKeys;
+import org.apache.ambari.server.ldap.domain.AmbariLdapConfiguration;
+import org.apache.ambari.server.ldap.service.AmbariLdapException;
+import org.apache.ambari.server.ldap.service.AttributeDetector;
+import org.apache.ambari.server.ldap.service.LdapAttributeDetectionService;
+import org.apache.ambari.server.ldap.service.ads.detectors.AttributeDetectorFactory;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.message.SearchRequest;
+import org.apache.directory.api.ldap.model.message.SearchScope;
+import org.apache.directory.api.util.Strings;
+import org.apache.directory.ldap.client.api.search.FilterBuilder;
+import org.apache.directory.ldap.client.template.EntryMapper;
+import org.apache.directory.ldap.client.template.LdapConnectionTemplate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Service implementation that performs user and group attribute detection based on a sample set of entries returned by
+ * an ldap search operation. A accuracy of detected values may depend on the size of the sample result set
+ */
+@Singleton
+public class DefaultLdapAttributeDetectionService implements LdapAttributeDetectionService {
+
+  private static final Logger LOG = LoggerFactory.getLogger(DefaultLdapAttributeDetectionService.class);
+
+  /**
+   * The maximum size of the entry set the detection is performed on
+   */
+  private static final int SAMPLE_RESULT_SIZE = 50;
+
+  @Inject
+  private AttributeDetectorFactory attributeDetectorFactory;
+
+  @Inject
+  private LdapConnectionTemplateFactory ldapConnectionTemplateFactory;
+
+  @Inject
+  public DefaultLdapAttributeDetectionService() {
+  }
+
+  @Override
+  public AmbariLdapConfiguration detectLdapUserAttributes(AmbariLdapConfiguration ambariLdapConfiguration) throws AmbariLdapException {
+    LOG.info("Detecting LDAP user attributes ...");
+
+    // perform a search using the user search base
+    if (Strings.isEmpty(ambariLdapConfiguration.userSearchBase())) {
+      LOG.warn("No user search base provided");
+      return ambariLdapConfiguration;
+    }
+
+    try {
+
+      LdapConnectionTemplate ldapConnectionTemplate = ldapConnectionTemplateFactory.create(ambariLdapConfiguration);
+      AttributeDetector<Entry> userAttributeDetector = attributeDetectorFactory.userAttributDetector();
+
+      SearchRequest searchRequest = assembleUserSearchRequest(ldapConnectionTemplate, ambariLdapConfiguration);
+
+      // do the search
+      List<Entry> entries = ldapConnectionTemplate.search(searchRequest, getEntryMapper());
+
+      for (Entry entry : entries) {
+        LOG.info("Collecting user attribute information from the sample entry with dn: [{}]", entry.getDn());
+        userAttributeDetector.collect(entry);
+      }
+
+      // select attributes based on the collected information
+      Map<String, String> detectedUserAttributes = userAttributeDetector.detect();
+
+      // setting the attributes into the configuration
+      setDetectedAttributes(ambariLdapConfiguration, detectedUserAttributes);
+
+      LOG.info("Decorated ambari ldap config : [{}]", ambariLdapConfiguration);
+
+    } catch (Exception e) {
+
+      LOG.error("Ldap operation failed while detecting user attributes", e);
+      throw new AmbariLdapException(e);
+
+    }
+
+    return ambariLdapConfiguration;
+  }
+
+
+  @Override
+  public AmbariLdapConfiguration detectLdapGroupAttributes(AmbariLdapConfiguration ambariLdapConfiguration) throws AmbariLdapException {
+    LOG.info("Detecting LDAP group attributes ...");
+
+    // perform a search using the user search base
+    if (Strings.isEmpty(ambariLdapConfiguration.groupSearchBase())) {
+      LOG.warn("No group search base provided");
+      return ambariLdapConfiguration;
+    }
+
+    try {
+
+      LdapConnectionTemplate ldapConnectionTemplate = ldapConnectionTemplateFactory.create(ambariLdapConfiguration);
+      AttributeDetector<Entry> groupAttributeDetector = attributeDetectorFactory.groupAttributeDetector();
+
+      SearchRequest searchRequest = assembleGroupSearchRequest(ldapConnectionTemplate, ambariLdapConfiguration);
+
+      // do the search
+      List<Entry> groupEntries = ldapConnectionTemplate.search(searchRequest, getEntryMapper());
+
+      for (Entry groupEntry : groupEntries) {
+
+        LOG.info("Collecting group attribute information from the sample entry with dn: [{}]", groupEntry.getDn());
+        groupAttributeDetector.collect(groupEntry);
+
+      }
+
+      // select attributes based on the collected information
+      Map<String, String> detectedGroupAttributes = groupAttributeDetector.detect();
+
+      // setting the attributes into the configuration
+      setDetectedAttributes(ambariLdapConfiguration, detectedGroupAttributes);
+
+      LOG.info("Decorated ambari ldap config : [{}]", ambariLdapConfiguration);
+
+    } catch (Exception e) {
+
+      LOG.error("Ldap operation failed while detecting group attributes", e);
+      throw new AmbariLdapException(e);
+
+    }
+
+    return ambariLdapConfiguration;
+  }
+
+  private void setDetectedAttributes(AmbariLdapConfiguration ambariLdapConfiguration, Map<String, String> detectedAttributes) {
+
+    for (Map.Entry<String, String> detecteMapEntry : detectedAttributes.entrySet()) {
+      LOG.info("Setting detected configuration value: [{}] - > [{}]", detecteMapEntry.getKey(), detecteMapEntry.getValue());
+      ambariLdapConfiguration.setValueFor(AmbariLdapConfigKeys.fromKeyStr(detecteMapEntry.getKey()), detecteMapEntry.getValue());
+    }
+
+  }
+
+  private SearchRequest assembleUserSearchRequest(LdapConnectionTemplate ldapConnectionTemplate, AmbariLdapConfiguration ambariLdapConfiguration) throws AmbariLdapException {
+    try {
+
+      SearchRequest req = ldapConnectionTemplate.newSearchRequest(ambariLdapConfiguration.userSearchBase(),
+        FilterBuilder.present(ambariLdapConfiguration.dnAttribute()).toString(), SearchScope.SUBTREE);
+      req.setSizeLimit(SAMPLE_RESULT_SIZE);
+
+      return req;
+
+    } catch (Exception e) {
+      LOG.error("Could not assemble ldap search request", e);
+      throw new AmbariLdapException(e);
+    }
+  }
+
+  private SearchRequest assembleGroupSearchRequest(LdapConnectionTemplate ldapConnectionTemplate, AmbariLdapConfiguration ambariLdapConfiguration) throws AmbariLdapException {
+    try {
+
+      SearchRequest req = ldapConnectionTemplate.newSearchRequest(ambariLdapConfiguration.groupSearchBase(),
+        FilterBuilder.present(ambariLdapConfiguration.dnAttribute()).toString(), SearchScope.SUBTREE);
+      req.setSizeLimit(SAMPLE_RESULT_SIZE);
+
+      return req;
+
+    } catch (Exception e) {
+      LOG.error("Could not assemble ldap search request", e);
+      throw new AmbariLdapException(e);
+    }
+  }
+
+  public EntryMapper<Entry> getEntryMapper() {
+    return new EntryMapper<Entry>() {
+      @Override
+      public Entry map(Entry entry) throws LdapException {
+        return entry;
+      }
+    };
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/6b7a7a70/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/DefaultLdapConfigurationService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/DefaultLdapConfigurationService.java b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/DefaultLdapConfigurationService.java
new file mode 100644
index 0000000..3f6995c
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/DefaultLdapConfigurationService.java
@@ -0,0 +1,213 @@
+/*
+ * Licensed 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.ldap.service.ads;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.apache.ambari.server.ldap.domain.AmbariLdapConfiguration;
+import org.apache.ambari.server.ldap.service.AmbariLdapException;
+import org.apache.ambari.server.ldap.service.LdapConfigurationService;
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.message.SearchRequest;
+import org.apache.directory.api.ldap.model.message.SearchScope;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.ldap.client.api.LdapConnection;
+import org.apache.directory.ldap.client.api.search.FilterBuilder;
+import org.apache.directory.ldap.client.template.ConnectionCallback;
+import org.apache.directory.ldap.client.template.EntryMapper;
+import org.apache.directory.ldap.client.template.LdapConnectionTemplate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+
+/**
+ * Implementation of the validation logic using the Apache Directory API.
+ */
+@Singleton
+public class DefaultLdapConfigurationService implements LdapConfigurationService {
+
+  private static final Logger LOGGER = LoggerFactory.getLogger(DefaultLdapConfigurationService.class);
+
+  @Inject
+  private LdapConnectionTemplateFactory ldapConnectionTemplateFactory;
+
+  @Inject
+  public DefaultLdapConfigurationService() {
+  }
+
+
+  @Override
+  public void checkConnection(AmbariLdapConfiguration ambariLdapConfiguration) throws AmbariLdapException {
+    LOGGER.info("Trying to connect to the LDAP server using provided configuration...");
+    LdapConnectionTemplate ldapConnectionTemplate = ldapConnectionTemplateFactory.create(ambariLdapConfiguration);
+
+    // check if the connection from the connection pool of the template is connected
+    Boolean isConnected = ldapConnectionTemplate.execute(new ConnectionCallback<Boolean>() {
+      @Override
+      public Boolean doWithConnection(LdapConnection connection) throws LdapException {
+        return connection.isConnected() && connection.isAuthenticated();
+      }
+    });
+
+    if (!isConnected) {
+      LOGGER.error("Could not connect to the LDAP server");
+      throw new AmbariLdapException("Could not connect to the LDAP server. Configuration: " + ambariLdapConfiguration);
+    }
+
+    LOGGER.info("Successfully conencted to the LDAP.");
+
+  }
+
+  /**
+   * Checks the user attributes provided in the configuration instance by issuing a search for a (known) test user in the LDAP.
+   * Attributes are considered correct if there is at least one entry found.
+   *
+   * Invalid attributes are signaled by throwing an exception.
+   *
+   * @param testUserName            the test username
+   * @param testPassword            the test password
+   * @param ambariLdapConfiguration the available LDAP configuration to be validated
+   * @return the DN of the test user
+   * @throws AmbariLdapException if an error occurs
+   */
+  @Override
+  public String checkUserAttributes(String testUserName, String testPassword, AmbariLdapConfiguration ambariLdapConfiguration) throws AmbariLdapException {
+    String userDn;
+    try {
+      LOGGER.info("Checking user attributes for user [{}] ...", testUserName);
+
+      // set up a filter based on the provided attributes
+      String filter = FilterBuilder.and(
+        FilterBuilder.equal(SchemaConstants.OBJECT_CLASS_AT, ambariLdapConfiguration.userObjectClass()),
+        FilterBuilder.equal(ambariLdapConfiguration.userNameAttribute(), testUserName))
+        .toString();
+
+      LOGGER.info("Searching for the user: [{}] using the search filter: [{}]", testUserName, filter);
+      userDn = ldapConnectionTemplateFactory.create(ambariLdapConfiguration).searchFirst(new Dn(ambariLdapConfiguration.userSearchBase()), filter, SearchScope.SUBTREE, getUserDnNameEntryMapper(ambariLdapConfiguration));
+
+      if (null == userDn) {
+        LOGGER.info("Could not find user based on the provided configuration. User attributes are not complete ");
+        throw new AmbariLdapException("User attribute configuration incomplete");
+      }
+      LOGGER.info("Attribute validation succeeded. Filter: [{}]", filter);
+
+
+    } catch (Exception e) {
+
+      LOGGER.error("User attributes validation failed.", e);
+      throw new AmbariLdapException(e.getMessage(), e);
+
+    }
+    return userDn;
+  }
+
+  /**
+   * Checks whether the provided group related settings are correct.
+   *
+   * @param userDn                  a user DN to check
+   * @param ambariLdapConfiguration the available LDAP configuration to be validated
+   * @return
+   * @throws AmbariLdapException
+   */
+  @Override
+  public Set<String> checkGroupAttributes(String userDn, AmbariLdapConfiguration ambariLdapConfiguration) throws AmbariLdapException {
+    List<String> groups = Lists.newArrayList();
+    try {
+      LOGGER.info("Checking group attributes for user dn: [{}] ...", userDn);
+
+      // set up a filter based on the provided attributes
+      String filter = FilterBuilder.and(
+        FilterBuilder.equal(SchemaConstants.OBJECT_CLASS_AT, ambariLdapConfiguration.groupObjectClass()),
+        FilterBuilder.equal(ambariLdapConfiguration.groupMemberAttribute(), userDn)
+      ).toString();
+
+      LOGGER.info("Searching for the groups the user dn: [{}] is member of using the search filter: [{}]", userDn, filter);
+      LdapConnectionTemplate ldapConnectionTemplate = ldapConnectionTemplateFactory.create(ambariLdapConfiguration);
+
+      // assemble a search request
+      SearchRequest searchRequest = ldapConnectionTemplate.newSearchRequest(new Dn(ambariLdapConfiguration.groupSearchBase()), filter, SearchScope.SUBTREE);
+      // attributes to be returned
+      searchRequest.addAttributes(ambariLdapConfiguration.groupMemberAttribute(), ambariLdapConfiguration.groupNameAttribute());
+
+      // perform the search
+      groups = ldapConnectionTemplate.search(searchRequest, getGroupNameEntryMapper(ambariLdapConfiguration));
+
+      if (groups == null || groups.isEmpty()) {
+        LOGGER.info("No groups found for the user dn. Group attributes configuration is incomplete");
+        throw new AmbariLdapException("Group attribute ldap configuration is incomplete");
+      }
+
+      LOGGER.info("Group attribute configuration check succeeded.");
+
+    } catch (Exception e) {
+
+      LOGGER.error("User attributes validation failed.", e);
+      throw new AmbariLdapException(e.getMessage(), e);
+
+    }
+
+    return new HashSet<>(groups);
+  }
+
+
+  /**
+   * Entry mapper for handling user search results.
+   *
+   * @param ambariLdapConfiguration ambari ldap configuration values
+   * @return user dn entry mapper instance
+   */
+  private EntryMapper<String> getGroupNameEntryMapper(AmbariLdapConfiguration ambariLdapConfiguration) {
+
+    EntryMapper<String> entryMapper = new EntryMapper<String>() {
+      @Override
+      public String map(Entry entry) throws LdapException {
+        return entry.get(ambariLdapConfiguration.groupNameAttribute()).get().getString();
+      }
+    };
+
+    return entryMapper;
+  }
+
+  /**
+   * Entry mapper for handling group searches.
+   *
+   * @param ambariLdapConfiguration ambari ldap configuration values
+   * @return
+   */
+  private EntryMapper<String> getUserDnNameEntryMapper(AmbariLdapConfiguration ambariLdapConfiguration) {
+
+    EntryMapper<String> entryMapper = new EntryMapper<String>() {
+      @Override
+      public String map(Entry entry) throws LdapException {
+        return entry.getDn().getNormName();
+      }
+    };
+
+    return entryMapper;
+  }
+
+
+}
+
+
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/6b7a7a70/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/DefaultLdapConnectionConfigService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/DefaultLdapConnectionConfigService.java b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/DefaultLdapConnectionConfigService.java
new file mode 100644
index 0000000..9afcf51
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/DefaultLdapConnectionConfigService.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed 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.ldap.service.ads;
+
+import static javax.net.ssl.TrustManagerFactory.getDefaultAlgorithm;
+
+import java.io.FileInputStream;
+import java.security.KeyStore;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+
+import org.apache.ambari.server.ldap.domain.AmbariLdapConfiguration;
+import org.apache.ambari.server.ldap.service.AmbariLdapException;
+import org.apache.ambari.server.ldap.service.LdapConnectionConfigService;
+import org.apache.directory.api.util.Strings;
+import org.apache.directory.ldap.client.api.LdapConnectionConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Singleton
+public class DefaultLdapConnectionConfigService implements LdapConnectionConfigService {
+
+  private static Logger LOG = LoggerFactory.getLogger(DefaultLdapConnectionConfigService.class);
+
+  @Inject
+  public DefaultLdapConnectionConfigService() {
+  }
+
+  @Override
+  public LdapConnectionConfig createLdapConnectionConfig(AmbariLdapConfiguration ambariLdapConfiguration) throws AmbariLdapException {
+
+    LOG.debug("Assembling ldap connection config based on: {}", ambariLdapConfiguration);
+
+    LdapConnectionConfig config = new LdapConnectionConfig();
+    config.setLdapHost(ambariLdapConfiguration.serverHost());
+    config.setLdapPort(ambariLdapConfiguration.serverPort());
+    config.setName(ambariLdapConfiguration.bindDn());
+    config.setCredentials(ambariLdapConfiguration.bindPassword());
+    config.setUseSsl(ambariLdapConfiguration.useSSL());
+
+    if ("custom".equals(ambariLdapConfiguration.trustStore())) {
+      LOG.info("Using custom trust manager configuration");
+      config.setTrustManagers(trustManagers(ambariLdapConfiguration));
+    }
+
+    return config;
+  }
+
+
+  /**
+   * Configure the trust managers to use the custom keystore.
+   *
+   * @param ambariLdapConfiguration congiguration instance holding current values
+   * @return the array of trust managers
+   * @throws AmbariLdapException if an error occurs while setting up the connection
+   */
+  private TrustManager[] trustManagers(AmbariLdapConfiguration ambariLdapConfiguration) throws AmbariLdapException {
+    try {
+
+      TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(getDefaultAlgorithm());
+      tmFactory.init(keyStore(ambariLdapConfiguration));
+      return tmFactory.getTrustManagers();
+
+    } catch (Exception e) {
+
+      LOG.error("Failed to initialize trust managers", e);
+      throw new AmbariLdapException(e);
+
+    }
+
+  }
+
+  private KeyStore keyStore(AmbariLdapConfiguration ambariLdapConfiguration) throws AmbariLdapException {
+
+    // validating configuration settings
+    if (Strings.isEmpty(ambariLdapConfiguration.trustStoreType())) {
+      throw new AmbariLdapException("Key Store Type must be specified");
+    }
+
+    if (Strings.isEmpty(ambariLdapConfiguration.trustStorePath())) {
+      throw new AmbariLdapException("Key Store Path must be specified");
+    }
+
+    try {
+
+      KeyStore ks = KeyStore.getInstance(ambariLdapConfiguration.trustStoreType());
+      FileInputStream fis = new FileInputStream(ambariLdapConfiguration.trustStorePath());
+      ks.load(fis, ambariLdapConfiguration.trustStorePassword().toCharArray());
+      return ks;
+
+    } catch (Exception e) {
+
+      LOG.error("Failed to create keystore", e);
+      throw new AmbariLdapException(e);
+
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/6b7a7a70/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/LdapConnectionTemplateFactory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/LdapConnectionTemplateFactory.java b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/LdapConnectionTemplateFactory.java
new file mode 100644
index 0000000..8467af0
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/LdapConnectionTemplateFactory.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed 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.ldap.service.ads;
+
+import javax.inject.Inject;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+
+import org.apache.ambari.server.events.AmbariLdapConfigChangedEvent;
+import org.apache.ambari.server.ldap.domain.AmbariLdapConfiguration;
+import org.apache.ambari.server.ldap.service.AmbariLdapException;
+import org.apache.ambari.server.ldap.service.LdapConnectionConfigService;
+import org.apache.directory.ldap.client.api.DefaultLdapConnectionFactory;
+import org.apache.directory.ldap.client.api.LdapConnectionConfig;
+import org.apache.directory.ldap.client.api.LdapConnectionFactory;
+import org.apache.directory.ldap.client.api.LdapConnectionPool;
+import org.apache.directory.ldap.client.api.ValidatingPoolableLdapConnectionFactory;
+import org.apache.directory.ldap.client.template.LdapConnectionTemplate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.eventbus.Subscribe;
+
+/**
+ * Factory for creating LdapConnectionTemplate instances.
+ * Depending on the usage context, the instance can be constructed based on the provided configuration or based on the persisted settings.
+ */
+@Singleton
+public class LdapConnectionTemplateFactory {
+
+  private static final Logger LOG = LoggerFactory.getLogger(LdapConnectionTemplateFactory.class);
+
+  // Inject the persisted configuration (when available) check the provider implementation for details.
+  @Inject
+  private Provider<AmbariLdapConfiguration> ambariLdapConfigurationProvider;
+
+
+  @Inject
+  private LdapConnectionConfigService ldapConnectionConfigService;
+
+  // cached instance that only changes when the underlying configuration changes.
+  private LdapConnectionTemplate ldapConnectionTemplateInstance;
+
+
+  @Inject
+  public LdapConnectionTemplateFactory() {
+  }
+
+  /**
+   * Creates a new instance based on the provided configuration. Use this factory method whle operating with ambari configuration not yet persisted.
+   *
+   * @param ambariLdapConfiguration ambari ldap configuration instance
+   * @return an instance of LdapConnectionTemplate
+   */
+  public LdapConnectionTemplate create(AmbariLdapConfiguration ambariLdapConfiguration) throws AmbariLdapException {
+    LOG.info("Constructing new instance based on the provided ambari ldap configuration: {}", ambariLdapConfiguration);
+
+    // create the connection config
+    LdapConnectionConfig ldapConnectionConfig = ldapConnectionConfigService.createLdapConnectionConfig(ambariLdapConfiguration);
+
+    // create the connection factory
+    LdapConnectionFactory ldapConnectionFactory = new DefaultLdapConnectionFactory(ldapConnectionConfig);
+
+    // create the connection pool
+    LdapConnectionPool ldapConnectionPool = new LdapConnectionPool(new ValidatingPoolableLdapConnectionFactory(ldapConnectionFactory));
+
+    LdapConnectionTemplate template = new LdapConnectionTemplate(ldapConnectionPool);
+    LOG.info("Ldap connection template instance: {}", template);
+
+    return template;
+
+  }
+
+  /**
+   * Loads the persisted LDAP configuration.
+   *
+   * @return theh persisted
+   */
+  public LdapConnectionTemplate load() throws AmbariLdapException {
+
+    if (null == ldapConnectionTemplateInstance) {
+      ldapConnectionTemplateInstance = create(ambariLdapConfigurationProvider.get());
+    }
+    return ldapConnectionTemplateInstance;
+  }
+
+  /**
+   * The returned connection template instance is recreated whenever the ambari ldap configuration changes
+   *
+   * @param event
+   * @throws AmbariLdapException
+   */
+  @Subscribe
+  public void onConfigChange(AmbariLdapConfigChangedEvent event) throws AmbariLdapException {
+    ldapConnectionTemplateInstance = create(ambariLdapConfigurationProvider.get());
+  }
+
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/6b7a7a70/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/detectors/AttributeDetectorFactory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/detectors/AttributeDetectorFactory.java b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/detectors/AttributeDetectorFactory.java
new file mode 100644
index 0000000..eba0bd9
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/detectors/AttributeDetectorFactory.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed 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.ldap.service.ads.detectors;
+
+import java.util.Set;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.apache.ambari.server.ldap.service.AttributeDetector;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Factory for attribute detector chains.
+ */
+@Singleton
+public class AttributeDetectorFactory {
+
+  private static final Logger LOG = LoggerFactory.getLogger(AttributeDetectorFactory.class);
+  private static final String USER_ATTRIBUTES_DETECTORS = "UserAttributesDetectors";
+  private static final String GROUP_ATTRIBUTES_DETECTORS = "GroupAttributesDetectors";
+  /**
+   * The set of group attribute detectors, configured by GUICE (check the relevant guice module implementation)
+   */
+  @Inject
+  @Named(GROUP_ATTRIBUTES_DETECTORS)
+  Set<AttributeDetector> groupAttributeDetectors;
+  /**
+   * The set of user attribute detectors, configured by GUICE (check the relevant guice module implementation)
+   */
+  @Inject
+  @Named(USER_ATTRIBUTES_DETECTORS)
+  private Set<AttributeDetector> userAttributeDetectors;
+
+  @Inject
+  public AttributeDetectorFactory() {
+  }
+
+  /**
+   * Creates a chained attribute detector instance with user attribute detectors
+   *
+   * @return the constructed ChainedAttributeDetector instance
+   */
+  public ChainedAttributeDetector userAttributDetector() {
+    LOG.info("Creating instance with user attribute detectors: [{}]", userAttributeDetectors);
+    return new ChainedAttributeDetector(userAttributeDetectors);
+  }
+
+  /**
+   * Creates a chained attribute detector instance with user attribute detectors
+   *
+   * @return the constructed ChainedAttributeDetector instance
+   */
+
+  public ChainedAttributeDetector groupAttributeDetector() {
+    LOG.info("Creating instance with group attribute detectors: [{}]", groupAttributeDetectors);
+    return new ChainedAttributeDetector(groupAttributeDetectors);
+  }
+
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/6b7a7a70/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/detectors/ChainedAttributeDetector.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/detectors/ChainedAttributeDetector.java b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/detectors/ChainedAttributeDetector.java
new file mode 100644
index 0000000..094922b
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/detectors/ChainedAttributeDetector.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed 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.ldap.service.ads.detectors;
+
+import java.util.Map;
+import java.util.Set;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.apache.ambari.server.ldap.service.AttributeDetector;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Maps;
+
+/**
+ * Attribute detector implementation that performs the attribute detection on a configured set of attribute detectors.
+ * (it implements the composite design pattern)
+ */
+@Singleton
+public class ChainedAttributeDetector implements AttributeDetector<Entry> {
+
+  private static final Logger LOG = LoggerFactory.getLogger(ChainedAttributeDetector.class);
+
+  /**
+   * The set of detectors this instance delegates to
+   */
+  private final Set<AttributeDetector> detectors;
+
+  @Inject
+  public ChainedAttributeDetector(Set<AttributeDetector> detectors) {
+    this.detectors = detectors;
+  }
+
+  @Override
+  public void collect(Entry entry) {
+    for (AttributeDetector detector : detectors) {
+      LOG.info("Collecting information for the detector: [{}]", detector);
+      detector.collect(entry);
+    }
+  }
+
+  @Override
+  public Map<String, String> detect() {
+    Map<String, String> detectedAttributes = Maps.newHashMap();
+    for (AttributeDetector detector : detectors) {
+      LOG.info("Detecting ldap configuration value using the detector: [{}]", detector);
+      detectedAttributes.putAll(detector.detect());
+    }
+    return detectedAttributes;
+  }
+
+  @Override
+  public String toString() {
+    return "ChainedAttributeDetector{" +
+      "detectors=" + detectors +
+      '}';
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/6b7a7a70/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/detectors/GroupMemberAttrDetector.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/detectors/GroupMemberAttrDetector.java b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/detectors/GroupMemberAttrDetector.java
new file mode 100644
index 0000000..8c34ef8
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/detectors/GroupMemberAttrDetector.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed 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.ldap.service.ads.detectors;
+
+import javax.inject.Inject;
+
+import org.apache.ambari.server.ldap.domain.AmbariLdapConfigKeys;
+import org.apache.directory.api.ldap.model.entry.Entry;
+
+public class GroupMemberAttrDetector extends OccurrenceAndWeightBasedDetector {
+
+  enum GroupMemberAttr {
+
+    MEMBER("member", 1),
+    MEMBER_UID("memberUid", 1),
+    UNIQUE_MEMBER("uniqueMember", 1);
+
+    private String attrName;
+    private Integer weight;
+
+    GroupMemberAttr(String attr, Integer weght) {
+      this.attrName = attr;
+      this.weight = weght;
+    }
+
+    Integer weight() {
+      return this.weight;
+    }
+
+    String attrName() {
+      return this.attrName;
+    }
+
+  }
+
+  @Inject
+  public GroupMemberAttrDetector() {
+    for (GroupMemberAttr groupMemberAttr : GroupMemberAttr.values()) {
+      occurrenceMap().put(groupMemberAttr.attrName(), 0);
+      weightsMap().put(groupMemberAttr.attrName(), groupMemberAttr.weight());
+    }
+  }
+
+  @Override
+  protected boolean applies(Entry entry, String attribute) {
+    return entry.containsAttribute(attribute);
+  }
+
+  @Override
+  public String detectedProperty() {
+    return AmbariLdapConfigKeys.GROUP_MEMBER_ATTRIBUTE.key();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/6b7a7a70/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/detectors/GroupNameAttrDetector.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/detectors/GroupNameAttrDetector.java b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/detectors/GroupNameAttrDetector.java
new file mode 100644
index 0000000..0315ef2
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/detectors/GroupNameAttrDetector.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed 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.ldap.service.ads.detectors;
+
+import javax.inject.Inject;
+
+import org.apache.ambari.server.ldap.domain.AmbariLdapConfigKeys;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class GroupNameAttrDetector extends OccurrenceAndWeightBasedDetector {
+  private static final Logger LOGGER = LoggerFactory.getLogger(UserNameAttrDetector.class);
+
+  private enum GroupNameAttr {
+
+    DISTINGUISHED_NAME("distinguishedName", 1),
+
+    CN("cn", 1);
+
+    private String attrName;
+    private Integer weight;
+
+    GroupNameAttr(String attr, Integer weght) {
+      this.attrName = attr;
+      this.weight = weght;
+    }
+
+    Integer weight() {
+      return this.weight;
+    }
+
+    String attrName() {
+      return this.attrName;
+    }
+
+  }
+
+  @Inject
+  public GroupNameAttrDetector() {
+
+    for (GroupNameAttr groupNameAttr : GroupNameAttr.values()) {
+      occurrenceMap().put(groupNameAttr.attrName(), 0);
+      weightsMap().put(groupNameAttr.attrName(), groupNameAttr.weight());
+    }
+  }
+
+
+  @Override
+  protected boolean applies(Entry entry, String attribute) {
+    return entry.containsAttribute(attribute);
+  }
+
+  @Override
+  public String detectedProperty() {
+    return AmbariLdapConfigKeys.GROUP_NAME_ATTRIBUTE.key();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/6b7a7a70/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/detectors/GroupObjectClassDetector.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/detectors/GroupObjectClassDetector.java b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/detectors/GroupObjectClassDetector.java
new file mode 100644
index 0000000..b681134
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/detectors/GroupObjectClassDetector.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed 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.ldap.service.ads.detectors;
+
+import javax.inject.Inject;
+
+import org.apache.ambari.server.ldap.domain.AmbariLdapConfigKeys;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class GroupObjectClassDetector extends OccurrenceAndWeightBasedDetector {
+
+  private static final Logger LOGGER = LoggerFactory.getLogger(GroupObjectClassDetector.class);
+
+  private enum ObjectClassValue {
+
+    GROUP("group", 1),
+
+    GROUP_OF_NAMES("groupOfNames", 1),
+
+    POSIX_GROUP("posixGroup", 1),
+
+    GROUP_OF_UNIQUE_NAMES("groupOfUniqueNames", 1);
+
+    private String ocVal;
+    private Integer weight;
+
+    ObjectClassValue(String attr, Integer weght) {
+      this.ocVal = attr;
+      this.weight = weght;
+    }
+
+    Integer weight() {
+      return this.weight;
+    }
+
+    String ocVal() {
+      return this.ocVal;
+    }
+
+  }
+
+  @Inject
+  public GroupObjectClassDetector() {
+    for (ObjectClassValue ocVal : ObjectClassValue.values()) {
+      occurrenceMap().put(ocVal.ocVal(), 0);
+      weightsMap().put(ocVal.ocVal(), ocVal.weight());
+    }
+  }
+
+  @Override
+  protected boolean applies(Entry entry, String attribute) {
+    return entry.hasObjectClass(attribute);
+  }
+
+  @Override
+  public String detectedProperty() {
+    return AmbariLdapConfigKeys.GROUP_OBJECT_CLASS.key();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/6b7a7a70/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/detectors/OccurrenceAndWeightBasedDetector.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/detectors/OccurrenceAndWeightBasedDetector.java b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/detectors/OccurrenceAndWeightBasedDetector.java
new file mode 100644
index 0000000..6ce7ca6
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/detectors/OccurrenceAndWeightBasedDetector.java
@@ -0,0 +1,143 @@
+/*
+ * Licensed 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.ldap.service.ads.detectors;
+
+import java.util.Map;
+
+import org.apache.ambari.server.ldap.service.AttributeDetector;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Maps;
+
+/**
+ * Attribute detector implementation that detects attributes considering their count of occurrence in a sample set of entries.
+ * When multiple values are checked these values can be assigned a weight, that represents it's importance.
+ */
+public abstract class OccurrenceAndWeightBasedDetector implements AttributeDetector<Entry> {
+
+  private static final Logger LOGGER = LoggerFactory.getLogger(OccurrenceAndWeightBasedDetector.class);
+
+  /**
+   * A map in which the keys are the attributes that are checked in an entry and the values are the number the key occurs
+   * in the sample entry set.
+   */
+  private Map<String, Integer> occurrenceMap = Maps.newHashMap();
+
+  /**
+   * A map in which the keys are the attributes that are checked in an entry and the values are the weight of the attribute.
+   */
+  private Map<String, Integer> weightsMap = Maps.newHashMap();
+
+  protected Map<String, Integer> occurrenceMap() {
+    return occurrenceMap;
+  }
+
+  protected Map<String, Integer> weightsMap() {
+    return weightsMap;
+  }
+
+
+  /**
+   * Checks whether the provided atribute is present in the entry.s
+   *
+   * @param entry     the entry being procesed
+   * @param attribute the attribute being detected
+   * @return true if the attribute is present, false otherwise
+   */
+  protected abstract boolean applies(Entry entry, String attribute);
+
+  /**
+   * The configuration key being detected.
+   *
+   * @return the key as a string
+   */
+  public abstract String detectedProperty();
+
+  /**
+   * Calculates the attribute value based on the two maps.
+   *
+   * @return a map with a single element, the key is the configuration key, the value is the detected attribute value
+   */
+  @Override
+  public Map<String, String> detect() {
+    LOGGER.info("Calculating the most probable attribute/value ...");
+    Map<String, String> detectedMap = Maps.newHashMap();
+
+    Map.Entry<String, Integer> selectedEntry = null;
+
+    for (Map.Entry<String, Integer> entry : occurrenceMap().entrySet()) {
+      if (selectedEntry == null) {
+
+        selectedEntry = entry;
+        LOGGER.debug("Initial attribute / value entry: {}", selectedEntry);
+        continue;
+
+      }
+
+      if (selectedEntry.getValue() < entry.getValue()) {
+
+        LOGGER.info("Changing potential attribute / value entry from : [{}] to: [{}]", selectedEntry, entry);
+        selectedEntry = entry;
+
+      }
+    }
+
+    // check whether the selected entry is valid (has occured in the sample result set)
+    String detectedVal = "N/A";
+
+    if (selectedEntry.getValue() > 0) {
+      detectedVal = selectedEntry.getKey();
+    } else {
+      LOGGER.warn("Unable to detect attribute or attribute value");
+    }
+
+    LOGGER.info("Detected attribute or value: [{}]", detectedVal);
+    detectedMap.put(detectedProperty(), detectedVal);
+    return detectedMap;
+  }
+
+
+  /**
+   * Collects the information about the attribute to be detected from the provided entry.
+   *
+   * @param entry a result entry returned by a search operation
+   */
+  @Override
+  public void collect(Entry entry) {
+    LOGGER.info("Collecting ldap attributes/values form entry with dn: [{}]", entry.getDn());
+
+    for (String attributeValue : occurrenceMap().keySet()) {
+      if (applies(entry, attributeValue)) {
+
+        Integer cnt = occurrenceMap().get(attributeValue).intValue();
+        if (weightsMap().containsKey(attributeValue)) {
+          cnt = cnt + weightsMap().get(attributeValue);
+        } else {
+          cnt = cnt + 1;
+        }
+        occurrenceMap().put(attributeValue, cnt);
+
+        LOGGER.info("Collected potential name attr: {}, count: {}", attributeValue, cnt);
+
+      } else {
+        LOGGER.info("The result entry doesn't contain the attribute: [{}]", attributeValue);
+      }
+    }
+  }
+
+
+}