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

rouazana pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 0b50da794a0bd00fef3758afe274fe30ba6a0053
Author: Tran Tien Duc <[email protected]>
AuthorDate: Tue Nov 12 16:36:31 2019 +0700

    JAMES-2905 Update ClientProvider to configure ES authentication
---
 .../apache/james/backends/es/ClientProvider.java   | 124 ++++++++++++++++++---
 1 file changed, 106 insertions(+), 18 deletions(-)

diff --git 
a/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/ClientProvider.java
 
b/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/ClientProvider.java
index 4f35e38..923a820 100644
--- 
a/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/ClientProvider.java
+++ 
b/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/ClientProvider.java
@@ -18,23 +18,35 @@
  ****************************************************************/
 package org.apache.james.backends.es;
 
+import java.io.File;
 import java.io.IOException;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
 import java.time.Duration;
 import java.time.LocalDateTime;
-import java.util.Optional;
 
 import javax.annotation.PreDestroy;
 import javax.inject.Inject;
 import javax.inject.Provider;
+import javax.net.ssl.SSLContext;
 
+import org.apache.commons.lang3.NotImplementedException;
 import org.apache.commons.lang3.time.DurationFormatUtils;
 import org.apache.http.HttpHost;
 import org.apache.http.auth.AuthScope;
 import org.apache.http.auth.UsernamePasswordCredentials;
 import org.apache.http.client.CredentialsProvider;
+import org.apache.http.conn.ssl.NoopHostnameVerifier;
 import org.apache.http.impl.client.BasicCredentialsProvider;
+import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
+import org.apache.http.ssl.SSLContextBuilder;
+import org.apache.http.ssl.TrustStrategy;
+import org.apache.james.backends.es.ElasticSearchConfiguration.HostScheme;
+import 
org.apache.james.backends.es.ElasticSearchConfiguration.SSLTrustConfiguration.SSLTrustStore;
+import 
org.apache.james.backends.es.ElasticSearchConfiguration.SSLTrustConfiguration.SSLValidationStrategy;
 import org.elasticsearch.client.RestClient;
-import org.elasticsearch.client.RestClientBuilder;
 import org.elasticsearch.client.RestHighLevelClient;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -46,14 +58,103 @@ import reactor.core.scheduler.Schedulers;
 
 public class ClientProvider implements Provider<RestHighLevelClient> {
 
+    private static class HttpAsyncClientConfigurer {
+
+        private static final TrustStrategy TRUST_ALL = (x509Certificates, 
authType) -> true;
+
+        private final ElasticSearchConfiguration configuration;
+
+        private HttpAsyncClientConfigurer(ElasticSearchConfiguration 
configuration) {
+            this.configuration = configuration;
+        }
+
+        private HttpAsyncClientBuilder configure(HttpAsyncClientBuilder 
builder) {
+            configureAuthentication(builder);
+            configureHostScheme(builder);
+
+            return builder;
+        }
+
+        private void configureHostScheme(HttpAsyncClientBuilder builder) {
+            HostScheme scheme = configuration.getHostScheme();
+
+            switch (scheme) {
+                case HTTP:
+                    return;
+                case HTTPS:
+                    configureSSLOptions(builder);
+                    return;
+                default:
+                    throw new NotImplementedException(
+                        String.format("unrecognized hostScheme '%s'", 
scheme.name()));
+            }
+        }
+
+        private void configureSSLOptions(HttpAsyncClientBuilder builder) {
+            try {
+                builder
+                    .setSSLContext(sslContext())
+                    .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE);
+            } catch (NoSuchAlgorithmException | KeyManagementException | 
KeyStoreException | CertificateException | IOException e) {
+                throw new RuntimeException("Cannot set SSL options to the 
builder", e);
+            }
+        }
+
+        private SSLContext sslContext() throws KeyStoreException, 
NoSuchAlgorithmException, KeyManagementException,
+            CertificateException, IOException {
+
+            SSLContextBuilder sslContextBuilder = new SSLContextBuilder();
+
+            SSLValidationStrategy strategy = 
configuration.getSslTrustConfiguration()
+                .getStrategy();
+
+            switch (strategy) {
+                case DEFAULT:
+                    return sslContextBuilder.build();
+                case IGNORE:
+                    return sslContextBuilder.loadTrustMaterial(TRUST_ALL)
+                        .build();
+                case OVERRIDE:
+                    return applyTrustStore(sslContextBuilder)
+                        .build();
+                default:
+                    throw new NotImplementedException(
+                        String.format("unrecognized strategy '%s'", 
strategy.name()));
+            }
+        }
+
+        private SSLContextBuilder applyTrustStore(SSLContextBuilder 
sslContextBuilder) throws CertificateException, NoSuchAlgorithmException,
+            KeyStoreException, IOException {
+
+            SSLTrustStore trustStore = configuration.getSslTrustConfiguration()
+                .getTrustStore()
+                .orElseThrow(() -> new IllegalStateException("SSLTrustStore 
cannot to be empty"));
+
+            return sslContextBuilder
+                .loadTrustMaterial(new File(trustStore.getFilePath()), 
trustStore.getPassword().toCharArray());
+        }
+
+        private void configureAuthentication(HttpAsyncClientBuilder builder) {
+            configuration.getCredential()
+                .ifPresent(credential -> {
+                    CredentialsProvider credentialsProvider = new 
BasicCredentialsProvider();
+                    credentialsProvider.setCredentials(AuthScope.ANY,
+                        new 
UsernamePasswordCredentials(credential.getUsername(), 
credential.getPassword()));
+                    builder.setDefaultCredentialsProvider(credentialsProvider);
+                });
+        }
+    }
+
     private static final Logger LOGGER = 
LoggerFactory.getLogger(ClientProvider.class);
 
     private final ElasticSearchConfiguration configuration;
     private final RestHighLevelClient client;
+    private final HttpAsyncClientConfigurer httpAsyncClientConfigurer;
 
     @Inject
     @VisibleForTesting
     ClientProvider(ElasticSearchConfiguration configuration) {
+        this.httpAsyncClientConfigurer = new 
HttpAsyncClientConfigurer(configuration);
         this.configuration = configuration;
         this.client = connect(configuration);
     }
@@ -73,27 +174,14 @@ public class ClientProvider implements 
Provider<RestHighLevelClient> {
 
     private RestHighLevelClient connectToCluster(ElasticSearchConfiguration 
configuration) {
         LOGGER.info("Trying to connect to ElasticSearch service at {}", 
LocalDateTime.now());
-        RestClientBuilder restClientBuilder = 
RestClient.builder(hostsToHttpHosts());
 
         return new RestHighLevelClient(
-            credentialsProvider(configuration)
-                .map(provider -> restClientBuilder.setHttpClientConfigCallback(
-                    httpClientBuilder -> 
httpClientBuilder.setDefaultCredentialsProvider(provider)))
-                .orElse(restClientBuilder)
+            RestClient
+                .builder(hostsToHttpHosts())
+                
.setHttpClientConfigCallback(httpAsyncClientConfigurer::configure)
                 
.setMaxRetryTimeoutMillis(Math.toIntExact(configuration.getRequestTimeout().toMillis())));
     }
 
-    private Optional<CredentialsProvider> 
credentialsProvider(ElasticSearchConfiguration configuration) {
-        return configuration.getCredential()
-            .map(credential -> {
-                CredentialsProvider credentialsProvider = new 
BasicCredentialsProvider();
-                credentialsProvider.setCredentials(AuthScope.ANY,
-                    new UsernamePasswordCredentials(credential.getUsername(), 
credential.getPassword()));
-
-                return credentialsProvider;
-            });
-    }
-
     private HttpHost[] hostsToHttpHosts() {
         return configuration.getHosts().stream()
             .map(host -> new HttpHost(host.getHostName(), host.getPort(), 
configuration.getHostScheme().name()))


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to