You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by ro...@apache.org on 2019/11/14 09:13:23 UTC
[james-project] 03/07: JAMES-2905 Update ClientProvider to
configure ES authentication
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 <dt...@linagora.com>
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: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org