AMBARI-21307 Ldapconnection template optimization, basic support for custom 
trust store


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/4bde7f62
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/4bde7f62
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/4bde7f62

Branch: refs/heads/feature-branch-AMBARI-21307
Commit: 4bde7f6204da89e0b91118f6838e4889e2f4947a
Parents: d501944
Author: lpuskas <lpus...@apache.org>
Authored: Mon Oct 9 17:20:38 2017 +0200
Committer: lpuskas <lpus...@apache.org>
Committed: Thu Oct 12 19:25:51 2017 +0200

----------------------------------------------------------------------
 .../apache/ambari/server/ldap/LdapModule.java   |   8 +-
 .../service/LdapAttributeDetectionService.java  |   4 +-
 .../service/LdapConnectionConfigService.java    |  34 ++++++
 .../service/LdapConnectionTemplateProvider.java |  56 ---------
 .../DefaultLdapAttributeDetectionService.java   |   4 +-
 .../ads/DefaultLdapConfigurationService.java    |  11 +-
 .../ads/LdapConnectionTemplateFactory.java      |  56 +++++----
 .../DefaultLdapConnectionConfigService.java     | 116 +++++++++++++++++++
 .../server/ldap/LdapModuleFunctionalTest.java   |  28 +++++
 9 files changed, 224 insertions(+), 93 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/4bde7f62/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
index d59264a..4abf4e7 100644
--- 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
@@ -21,11 +21,11 @@ import 
org.apache.ambari.server.ldap.service.AmbariLdapConfigurationProvider;
 import org.apache.ambari.server.ldap.service.AmbariLdapFacade;
 import org.apache.ambari.server.ldap.service.LdapAttributeDetectionService;
 import org.apache.ambari.server.ldap.service.LdapConfigurationService;
-import org.apache.ambari.server.ldap.service.LdapConnectionTemplateProvider;
+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.directory.ldap.client.template.LdapConnectionTemplate;
+import 
org.apache.ambari.server.ldap.service.ads.detectors.DefaultLdapConnectionConfigService;
 
 import com.google.inject.AbstractModule;
 import com.google.inject.assistedinject.FactoryModuleBuilder;
@@ -40,13 +40,11 @@ public class LdapModule extends AbstractModule {
     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 to the provider implementation (let GUICE deal with instantiating 
3rd party instances)
-    
bind(LdapConnectionTemplate.class).toProvider(LdapConnectionTemplateProvider.class);
-
     install(new 
FactoryModuleBuilder().build(AmbariLdapConfigurationFactory.class));
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bde7f62/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
index 6cd369b..c08a2e0 100644
--- 
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
@@ -27,7 +27,7 @@ public interface LdapAttributeDetectionService {
    * @param ambariLdapConfiguration configuration instance holding connection 
details
    * @return the configuration decorated with user related attributes
    */
-  AmbariLdapConfiguration detectLdapUserAttributes(AmbariLdapConfiguration 
ambariLdapConfiguration);
+  AmbariLdapConfiguration detectLdapUserAttributes(AmbariLdapConfiguration 
ambariLdapConfiguration) throws AmbariLdapException;
 
   /**
    * Decorates the passed in configuration with the detected ldap group 
attribute values
@@ -35,6 +35,6 @@ public interface LdapAttributeDetectionService {
    * @param ambariLdapConfiguration configuration instance holding connection 
details
    * @return the configuration decorated with group related attributes
    */
-  AmbariLdapConfiguration detectLdapGroupAttributes(AmbariLdapConfiguration 
ambariLdapConfiguration);
+  AmbariLdapConfiguration detectLdapGroupAttributes(AmbariLdapConfiguration 
ambariLdapConfiguration) throws AmbariLdapException;
 }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bde7f62/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..e2055bb
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/LdapConnectionConfigService.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.service;
+
+import org.apache.ambari.server.ldap.domain.AmbariLdapConfiguration;
+import org.apache.directory.ldap.client.api.LdapConnectionConfig;
+
+/**
+ * Contract for creating connection configuration instances
+ */
+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/4bde7f62/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/LdapConnectionTemplateProvider.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/LdapConnectionTemplateProvider.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/LdapConnectionTemplateProvider.java
deleted file mode 100644
index 5ed06e3..0000000
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/LdapConnectionTemplateProvider.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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 javax.inject.Inject;
-import javax.inject.Provider;
-
-import org.apache.ambari.server.ldap.domain.AmbariLdapConfiguration;
-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;
-
-public class LdapConnectionTemplateProvider implements 
Provider<LdapConnectionTemplate> {
-
-  // Inject the persisted configuration (when available) check the provider 
implementation for details.
-  @Inject
-  private Provider<AmbariLdapConfiguration> ambariLdapConfigurationProvider;
-
-  @Override
-  public LdapConnectionTemplate get() {
-    return new LdapConnectionTemplate(new LdapConnectionPool(
-      new 
ValidatingPoolableLdapConnectionFactory(getLdapConnectionFactory())));
-  }
-
-  private LdapConnectionConfig getLdapConnectionConfig() {
-    LdapConnectionConfig config = new LdapConnectionConfig();
-    config.setLdapHost(ambariLdapConfigurationProvider.get().serverHost());
-    config.setLdapPort(ambariLdapConfigurationProvider.get().serverPort());
-    config.setName(ambariLdapConfigurationProvider.get().bindDn());
-    
config.setCredentials(ambariLdapConfigurationProvider.get().bindPassword());
-
-    return config;
-  }
-
-  private LdapConnectionFactory getLdapConnectionFactory() {
-    return new DefaultLdapConnectionFactory(getLdapConnectionConfig());
-  }
-
-
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bde7f62/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
index 639d48d..204c46a 100644
--- 
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
@@ -73,7 +73,7 @@ public class DefaultLdapAttributeDetectionService implements 
LdapAttributeDetect
   }
 
   @Override
-  public AmbariLdapConfiguration 
detectLdapUserAttributes(AmbariLdapConfiguration ambariLdapConfiguration) {
+  public AmbariLdapConfiguration 
detectLdapUserAttributes(AmbariLdapConfiguration ambariLdapConfiguration) 
throws AmbariLdapException {
     LOGGER.info("Detecting LDAP user attributes ...");
     LdapConnectionTemplate ldapConnectionTemplate = 
ldapConnectionTemplateFactory.create(ambariLdapConfiguration);
 
@@ -116,7 +116,7 @@ public class DefaultLdapAttributeDetectionService 
implements LdapAttributeDetect
 
 
   @Override
-  public AmbariLdapConfiguration 
detectLdapGroupAttributes(AmbariLdapConfiguration ambariLdapConfiguration) {
+  public AmbariLdapConfiguration 
detectLdapGroupAttributes(AmbariLdapConfiguration ambariLdapConfiguration) 
throws AmbariLdapException {
     LOGGER.info("Detecting LDAP group attributes ...");
 
     // perform a search using the user search base

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bde7f62/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
index bbe4d0a..60c1272 100644
--- 
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
@@ -28,7 +28,6 @@ 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.SearchRequestImpl;
 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;
@@ -117,7 +116,6 @@ public class DefaultLdapConfigurationService implements 
LdapConfigurationService
 
   /**
    * Checks whether the provided group related settings are correct.
-   * The algorithm implemented in this method per
    *
    * @param userDn                  a user DN to check
    * @param ambariLdapConfiguration the available LDAP configuration to be 
validated
@@ -137,18 +135,15 @@ public class DefaultLdapConfigurationService implements 
LdapConfigurationService
       ).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 = new SearchRequestImpl();
-      searchRequest.setFilter(filter);
-      searchRequest.setBase(new Dn(ambariLdapConfiguration.groupSearchBase()));
-      searchRequest.setScope(SearchScope.SUBTREE);
+      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 = 
ldapConnectionTemplateFactory.create(ambariLdapConfiguration).search(searchRequest,
 getGroupNameEntryMapper(ambariLdapConfiguration));
-
+      groups = ldapConnectionTemplate.search(searchRequest, 
getGroupNameEntryMapper(ambariLdapConfiguration));
 
     } catch (Exception e) {
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/4bde7f62/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
index 50345bc..8467af0 100644
--- 
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
@@ -18,7 +18,10 @@ 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;
@@ -28,6 +31,8 @@ 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.
@@ -37,8 +42,17 @@ 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 Provider<LdapConnectionTemplate> ldapConnectionTemplate;
+  private LdapConnectionConfigService ldapConnectionConfigService;
+
+  // cached instance that only changes when the underlying configuration 
changes.
+  private LdapConnectionTemplate ldapConnectionTemplateInstance;
+
 
   @Inject
   public LdapConnectionTemplateFactory() {
@@ -50,11 +64,11 @@ public class LdapConnectionTemplateFactory {
    * @param ambariLdapConfiguration ambari ldap configuration instance
    * @return an instance of LdapConnectionTemplate
    */
-  public LdapConnectionTemplate create(AmbariLdapConfiguration 
ambariLdapConfiguration) {
+  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 = 
getLdapConnectionConfig(ambariLdapConfiguration);
+    LdapConnectionConfig ldapConnectionConfig = 
ldapConnectionConfigService.createLdapConnectionConfig(ambariLdapConfiguration);
 
     // create the connection factory
     LdapConnectionFactory ldapConnectionFactory = new 
DefaultLdapConnectionFactory(ldapConnectionConfig);
@@ -69,26 +83,28 @@ public class LdapConnectionTemplateFactory {
 
   }
 
-  public LdapConnectionTemplate load() {
-    // the construction logic is implemented in the provider class
-    return ldapConnectionTemplate.get();
-  }
-
-
-  private LdapConnectionConfig getLdapConnectionConfig(AmbariLdapConfiguration 
ambariLdapConfiguration) {
-
-    LdapConnectionConfig config = new LdapConnectionConfig();
-    config.setLdapHost(ambariLdapConfiguration.serverHost());
-    config.setLdapPort(ambariLdapConfiguration.serverPort());
-    config.setName(ambariLdapConfiguration.bindDn());
-    config.setCredentials(ambariLdapConfiguration.bindPassword());
+  /**
+   * Loads the persisted LDAP configuration.
+   *
+   * @return theh persisted
+   */
+  public LdapConnectionTemplate load() throws AmbariLdapException {
 
-    // todo set the other required properties here, eg.: trustmanager
-    return config;
+    if (null == ldapConnectionTemplateInstance) {
+      ldapConnectionTemplateInstance = 
create(ambariLdapConfigurationProvider.get());
+    }
+    return ldapConnectionTemplateInstance;
   }
 
-  private LdapConnectionFactory 
getLdapConnectionFactory(AmbariLdapConfiguration ambariLdapConfiguration) {
-    return new 
DefaultLdapConnectionFactory(getLdapConnectionConfig(ambariLdapConfiguration));
+  /**
+   * 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/4bde7f62/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/detectors/DefaultLdapConnectionConfigService.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/detectors/DefaultLdapConnectionConfigService.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/detectors/DefaultLdapConnectionConfigService.java
new file mode 100644
index 0000000..b12cc85
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/ldap/service/ads/detectors/DefaultLdapConnectionConfigService.java
@@ -0,0 +1,116 @@
+/*
+ * 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 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());
+
+    // todo implement proper validation logic here: identify 
optional/mandatory settings
+    // todo suggest proper naming
+    if ("custom".equals(ambariLdapConfiguration.trustStore())) {
+      LOG.info("Using custom trust manager configuration");
+      config.setTrustManagers(trustManagers(ambariLdapConfiguration));
+    }
+
+
+    return config;
+  }
+
+
+  /**
+   * Configure the trustmanagers 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/4bde7f62/ambari-server/src/test/java/org/apache/ambari/server/ldap/LdapModuleFunctionalTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/ldap/LdapModuleFunctionalTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/ldap/LdapModuleFunctionalTest.java
index 8059723..b9f140e 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/ldap/LdapModuleFunctionalTest.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/ldap/LdapModuleFunctionalTest.java
@@ -21,6 +21,7 @@ import 
org.apache.ambari.server.ldap.domain.AmbariLdapConfiguration;
 import 
org.apache.ambari.server.ldap.domain.TestAmbariAmbariLdapConfigurationFactory;
 import org.apache.ambari.server.ldap.service.LdapConfigurationService;
 import org.apache.ambari.server.ldap.service.LdapFacade;
+import org.apache.ambari.server.ldap.service.ads.LdapConnectionTemplateFactory;
 import org.apache.directory.api.ldap.model.constants.SchemaConstants;
 import org.apache.directory.api.ldap.model.exception.LdapException;
 import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
@@ -130,14 +131,41 @@ public class LdapModuleFunctionalTest {
     ldapPropsMap.put(AmbariLdapConfigKeys.SERVER_PORT.key(), "389");
     ldapPropsMap.put(AmbariLdapConfigKeys.BIND_DN.key(), 
"cn=read-only-admin,dc=example,dc=com");
     ldapPropsMap.put(AmbariLdapConfigKeys.BIND_PASSWORD.key(), "password");
+    ldapPropsMap.put(AmbariLdapConfigKeys.USE_SSL.key(), "true");
 
     ldapPropsMap.put(AmbariLdapConfigKeys.USER_OBJECT_CLASS.key(), 
SchemaConstants.PERSON_OC);
     ldapPropsMap.put(AmbariLdapConfigKeys.USER_NAME_ATTRIBUTE.key(), 
SchemaConstants.UID_AT);
     ldapPropsMap.put(AmbariLdapConfigKeys.USER_SEARCH_BASE.key(), 
"dc=example,dc=com");
     ldapPropsMap.put(AmbariLdapConfigKeys.DN_ATTRIBUTE.key(), 
SchemaConstants.UID_AT);
+    ldapPropsMap.put(AmbariLdapConfigKeys.TRUST_STORE.key(), "custom");
+    ldapPropsMap.put(AmbariLdapConfigKeys.TRUST_STORE_TYPE.key(), "JKS");
+    ldapPropsMap.put(AmbariLdapConfigKeys.TRUST_STORE_PATH.key(), 
"/Users/lpuskas/my_truststore/KeyStore.jks");
+    ldapPropsMap.put(AmbariLdapConfigKeys.TRUST_STORE_PASSWORD.key(), 
"lofasz");
 
 
     return ldapPropsMap;
   }
 
+
+  @Test
+  public void testShouldCustomTrustManagersBeSetForLdapConnection() throws 
Exception {
+    // GIVEN
+    AmbariLdapConfiguration ambariLdapConfiguration = 
ldapConfigurationFactory.createLdapConfiguration(getProps());
+
+    LdapFacade ldapFacade = injector.getInstance(LdapFacade.class);
+
+    LdapConnectionTemplateFactory lctFactory = 
injector.getInstance(LdapConnectionTemplateFactory.class);
+
+    LdapConnectionTemplate template1 = lctFactory.load();
+    LdapConnectionTemplate template2 = 
lctFactory.create(ambariLdapConfiguration);
+
+
+    // WHEN
+    ldapFacade.checkConnection(ambariLdapConfiguration);
+
+    ldapFacade.detectAttributes(ambariLdapConfiguration);
+
+    // THEN
+    // no exceptions thrown
+  }
 }
\ No newline at end of file

Reply via email to