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:22 UTC

[james-project] 02/07: JAMES-2905 DockerElasticSearch now has two types

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 870798f43e11be79bbcfdce8ed4e7ccc40f16cf0
Author: Tran Tien Duc <dt...@linagora.com>
AuthorDate: Tue Nov 12 16:35:47 2019 +0700

    JAMES-2905 DockerElasticSearch now has two types
    
     - No authentication
     - Has authentication
---
 .../james/backends/es/DockerElasticSearch.java     | 309 +++++++++++++++++----
 .../backends/es/DockerElasticSearchSingleton.java  |   2 +-
 .../backends/es/ElasticSearchClusterExtension.java | 115 ++++++++
 .../src/test/resources/auth-es/NginxDockerfile     |   5 +
 .../src/test/resources/auth-es/README.md           |  30 ++
 .../src/test/resources/auth-es/default.crt         |  19 ++
 .../src/test/resources/auth-es/default.key         |  27 ++
 .../src/test/resources/auth-es/nginx-conf/passwd   |   2 +
 .../auth-es/nginx-conf/reverse_elasticsearch.conf  |  12 +
 .../src/test/resources/auth-es/server.jks          | Bin 0 -> 1074 bytes
 ...esWithNonCompatibleElasticSearchServerTest.java |   2 +-
 .../apache/james/metric/es/ES2ReporterTest.java    |   2 +-
 .../apache/james/metric/es/ES6ReporterTest.java    |   2 +-
 .../apache/james/util/docker/DockerContainer.java  |  11 +
 14 files changed, 487 insertions(+), 51 deletions(-)

diff --git a/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/DockerElasticSearch.java b/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/DockerElasticSearch.java
index e3365b2..2424477 100644
--- a/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/DockerElasticSearch.java
+++ b/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/DockerElasticSearch.java
@@ -19,33 +19,98 @@
 
 package org.apache.james.backends.es;
 
+import static org.apache.james.backends.es.DockerElasticSearch.Fixture.ES_HTTP_PORT;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.security.cert.X509Certificate;
 import java.time.Duration;
 import java.util.Optional;
 
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
 import org.apache.http.HttpStatus;
+import org.apache.james.backends.es.ElasticSearchConfiguration.Credential;
+import org.apache.james.backends.es.ElasticSearchConfiguration.HostScheme;
 import org.apache.james.util.Host;
 import org.apache.james.util.docker.DockerContainer;
 import org.apache.james.util.docker.Images;
 import org.apache.james.util.docker.RateLimiters;
+import org.slf4j.LoggerFactory;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.containers.Network;
 import org.testcontainers.containers.wait.strategy.HostPortWaitStrategy;
+import org.testcontainers.images.builder.ImageFromDockerfile;
 
 import com.google.common.collect.ImmutableMap;
 
+import feign.Client;
 import feign.Feign;
 import feign.Logger;
 import feign.RequestLine;
 import feign.Response;
+import feign.auth.BasicAuthRequestInterceptor;
 import feign.slf4j.Slf4jLogger;
 
-public class DockerElasticSearch {
+public interface DockerElasticSearch {
 
     interface ElasticSearchAPI {
 
-        static ElasticSearchAPI from(Host esHttpHost) {
-            return Feign.builder()
-                .logger(new Slf4jLogger(ElasticSearchAPI.class))
-                .logLevel(Logger.Level.FULL)
-                .target(ElasticSearchAPI.class, "http://" + esHttpHost.getHostName() + ":" + esHttpHost.getPort());
+        class Builder {
+            private static final HostnameVerifier ACCEPT_ANY_HOST = (hostname1, sslSession) -> true;
+            private static final TrustManager[] TRUST_ALL = new TrustManager[] {
+                new X509TrustManager() {
+
+                    public X509Certificate[] getAcceptedIssuers() {
+                        return new X509Certificate[0];
+                    }
+                    public void checkClientTrusted(X509Certificate[] certs, String authType) {
+                    }
+                    public void checkServerTrusted(X509Certificate[] certs, String authType) {
+                    }
+                }
+            };
+
+            private final Feign.Builder requestBuilder;
+            private final URL esURL;
+
+            public Builder(URL esURL) {
+                this.esURL = esURL;
+                this.requestBuilder = Feign.builder()
+                    .logger(new Slf4jLogger(ElasticSearchAPI.class))
+                    .logLevel(Logger.Level.FULL);
+            }
+
+            public Builder credential(Credential credential) {
+                requestBuilder.requestInterceptor(
+                    new BasicAuthRequestInterceptor(credential.getUsername(), credential.getPassword()));
+                return this;
+            }
+
+            public Builder disableSSLValidation() throws Exception {
+                SSLContext sc = SSLContext.getInstance("SSL");
+                sc.init(null, TRUST_ALL, new java.security.SecureRandom());
+                SSLSocketFactory factory = sc.getSocketFactory();
+                HttpsURLConnection.setDefaultSSLSocketFactory(factory);
+                Client ignoredSSLClient = new Client.Default(factory, ACCEPT_ANY_HOST);
+
+                requestBuilder.client(ignoredSSLClient);
+
+                return this;
+            }
+
+            public ElasticSearchAPI build() {
+                return requestBuilder.target(ElasticSearchAPI.class, esURL.toString());
+            }
+        }
+
+        static Builder builder(URL esURL) {
+            return new Builder(esURL);
         }
 
         @RequestLine("DELETE /_all")
@@ -55,85 +120,235 @@ public class DockerElasticSearch {
         Response flush();
     }
 
-    private static final int ES_HTTP_PORT = 9200;
+    interface Fixture {
+        int ES_HTTP_PORT = 9200;
+    }
 
-    private final DockerContainer eSContainer;
+    class NoAuth implements DockerElasticSearch {
 
-    public DockerElasticSearch() {
-        this(Images.ELASTICSEARCH_6);
-    }
+        static DockerContainer defaultContainer(String imageName) {
+            return DockerContainer.fromName(imageName)
+                .withTmpFs(ImmutableMap.of("/usr/share/elasticsearch/data", "rw,size=200m"))
+                .withExposedPorts(ES_HTTP_PORT)
+                .withEnv("discovery.type", "single-node")
+                .withAffinityToContainer()
+                .waitingFor(new HostPortWaitStrategy().withRateLimiter(RateLimiters.TWENTIES_PER_SECOND));
+        }
 
-    public DockerElasticSearch(String imageName) {
-        this.eSContainer = DockerContainer.fromName(imageName)
-            .withTmpFs(ImmutableMap.of("/usr/share/elasticsearch/data", "rw,size=200m"))
-            .withExposedPorts(ES_HTTP_PORT)
-            .withEnv("discovery.type", "single-node")
-            .withAffinityToContainer()
-            .waitingFor(new HostPortWaitStrategy().withRateLimiter(RateLimiters.TWENTIES_PER_SECOND));
-    }
+        private final DockerContainer eSContainer;
 
-    public void start() {
-        if (!eSContainer.isRunning()) {
-            eSContainer.start();
+        public NoAuth() {
+            this(Images.ELASTICSEARCH_6);
         }
-    }
 
-    public void stop() {
-        eSContainer.stop();
-    }
+        public NoAuth(String imageName) {
+            this.eSContainer = defaultContainer(imageName);
+        }
 
-    public int getHttpPort() {
-        return eSContainer.getMappedPort(ES_HTTP_PORT);
-    }
+        public NoAuth(DockerContainer eSContainer) {
+            this.eSContainer = eSContainer;
+        }
+
+        public void start() {
+            if (!isRunning()) {
+                eSContainer.start();
+            }
+        }
+
+        public void stop() {
+            eSContainer.stop();
+        }
+
+        public int getHttpPort() {
+            return eSContainer.getMappedPort(ES_HTTP_PORT);
+        }
+
+        public String getIp() {
+            return eSContainer.getHostIp();
+        }
+
+        public Host getHttpHost() {
+            return Host.from(getIp(), getHttpPort());
+        }
+
+        public void pause() {
+            eSContainer.pause();
+        }
+
+        public void unpause() {
+            eSContainer.unpause();
+        }
 
-    public String getIp() {
-        return eSContainer.getHostIp();
+        @Override
+        public boolean isRunning() {
+            return eSContainer.isRunning();
+        }
     }
 
-    public Host getHttpHost() {
-        return Host.from(getIp(), getHttpPort());
+    class WithAuth implements DockerElasticSearch {
+
+        private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(WithAuth.class);
+
+        private static final String DEFAULT_USERNAME = "elasticsearch";
+        private static final String DEFAULT_PASSWORD = "secret";
+        public static final Credential DEFAULT_CREDENTIAL =
+            Credential.of(DEFAULT_USERNAME, DEFAULT_PASSWORD);
+
+        private final DockerElasticSearch.NoAuth elasticSearch;
+        private final DockerContainer nginx;
+        private final Network network;
+
+        public WithAuth() {
+            this(Images.ELASTICSEARCH_6);
+        }
+
+        WithAuth(String imageName) {
+            this.network = Network.newNetwork();
+            this.elasticSearch = new DockerElasticSearch.NoAuth(
+                DockerElasticSearch.NoAuth
+                    .defaultContainer(imageName)
+                    .withLogConsumer(frame -> LOGGER.debug("[ElasticSearch] " + frame.getUtf8String()))
+                    .withNetwork(network)
+                    .withNetworkAliases("elasticsearch"));
+
+            this.nginx = new DockerContainer(
+                    new GenericContainer<>(
+                        new ImageFromDockerfile()
+                        .withFileFromClasspath("conf/nginx-conf/", "auth-es/nginx-conf/")
+                        .withFileFromClasspath("conf/default.crt", "auth-es/default.crt")
+                        .withFileFromClasspath("conf/default.key", "auth-es/default.key")
+                        .withFileFromClasspath("Dockerfile", "auth-es/NginxDockerfile")))
+                .withExposedPorts(ES_HTTP_PORT)
+                .withLogConsumer(frame -> LOGGER.debug("[NGINX] " + frame.getUtf8String()))
+                .withNetwork(network);
+        }
+
+
+        public void start() {
+            elasticSearch.start();
+            nginx.start();
+        }
+
+        public void stop() {
+            nginx.stop();
+            elasticSearch.stop();
+        }
+
+        public int getHttpPort() {
+            return nginx.getMappedPort(ES_HTTP_PORT);
+        }
+
+        public String getIp() {
+            return nginx.getHostIp();
+        }
+
+        @Override
+        public ElasticSearchAPI esAPI() {
+            try {
+                return ElasticSearchAPI.builder(getUrl())
+                    .credential(DEFAULT_CREDENTIAL)
+                    .disableSSLValidation()
+                    .build();
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        @Override
+        public URL getUrl() {
+            try {
+                return new URL("https://" + getIp() + ":" + getHttpPort());
+            } catch (MalformedURLException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        @Override
+        public ElasticSearchConfiguration configuration(Optional<Duration> requestTimeout) {
+            return configurationBuilder(requestTimeout)
+                .hostScheme(Optional.of(HostScheme.HTTPS))
+                .build();
+        }
+
+        public void pause() {
+            nginx.pause();
+            elasticSearch.pause();
+        }
+
+        public void unpause() {
+            elasticSearch.unpause();
+            nginx.unpause();
+        }
+
+        @Override
+        public boolean isRunning() {
+            return nginx.isRunning() && elasticSearch.isRunning();
+        }
     }
 
-    public void pause() {
-        eSContainer.pause();
+    void start();
+
+    void stop();
+
+    int getHttpPort();
+
+    String getIp();
+
+    void pause();
+
+    void unpause();
+
+    boolean isRunning();
+
+    default URL getUrl() {
+        try {
+            return new URL("http://" + getIp() + ":" + getHttpPort());
+        } catch (MalformedURLException e) {
+            throw new RuntimeException(e);
+        }
     }
 
-    public void unpause() {
-        eSContainer.unpause();
+    default Host getHttpHost() {
+        return Host.from(getIp(), getHttpPort());
     }
 
-    public void cleanUpData() {
+    default void cleanUpData() {
         if (esAPI().deleteAllIndexes().status() != HttpStatus.SC_OK) {
             throw new IllegalStateException("Failed to delete all data from ElasticSearch");
         }
     }
 
-    public void flushIndices() {
+    default void flushIndices() {
         if (esAPI().flush().status() != HttpStatus.SC_OK) {
             throw new IllegalStateException("Failed to flush ElasticSearch");
         }
     }
 
-    public ElasticSearchConfiguration configuration(Optional<Duration> requestTimeout) {
+    default ElasticSearchConfiguration configuration(Optional<Duration> requestTimeout) {
+        return configurationBuilder(requestTimeout)
+            .build();
+    }
+
+    default ElasticSearchConfiguration.Builder configurationBuilder(Optional<Duration> requestTimeout) {
         return ElasticSearchConfiguration.builder()
             .addHost(getHttpHost())
-            .requestTimeout(requestTimeout)
-            .build();
+            .requestTimeout(requestTimeout);
     }
 
-    public ElasticSearchConfiguration configuration() {
+    default ElasticSearchConfiguration configuration() {
         return configuration(Optional.empty());
     }
 
-    public ClientProvider clientProvider() {
+    default ClientProvider clientProvider() {
         return new ClientProvider(configuration(Optional.empty()));
     }
 
-    public ClientProvider clientProvider(Duration requestTimeout) {
+    default ClientProvider clientProvider(Duration requestTimeout) {
         return new ClientProvider(configuration(Optional.of(requestTimeout)));
     }
 
-    private ElasticSearchAPI esAPI() {
-        return ElasticSearchAPI.from(getHttpHost());
+    default ElasticSearchAPI esAPI() {
+        return ElasticSearchAPI.builder(getUrl())
+            .build();
     }
 }
diff --git a/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/DockerElasticSearchSingleton.java b/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/DockerElasticSearchSingleton.java
index e3d409a..2175b34 100644
--- a/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/DockerElasticSearchSingleton.java
+++ b/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/DockerElasticSearchSingleton.java
@@ -20,7 +20,7 @@
 package org.apache.james.backends.es;
 
 public class DockerElasticSearchSingleton {
-    public static DockerElasticSearch INSTANCE = new DockerElasticSearch();
+    public static DockerElasticSearch INSTANCE = new DockerElasticSearch.NoAuth();
 
     static {
         INSTANCE.start();
diff --git a/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/ElasticSearchClusterExtension.java b/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/ElasticSearchClusterExtension.java
new file mode 100644
index 0000000..3e73fe0
--- /dev/null
+++ b/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/ElasticSearchClusterExtension.java
@@ -0,0 +1,115 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.backends.es;
+
+import java.util.List;
+import java.util.function.Function;
+import java.util.stream.Stream;
+
+import org.apache.james.util.Host;
+import org.junit.jupiter.api.extension.AfterAllCallback;
+import org.junit.jupiter.api.extension.AfterEachCallback;
+import org.junit.jupiter.api.extension.BeforeAllCallback;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.jupiter.api.extension.ParameterContext;
+import org.junit.jupiter.api.extension.ParameterResolutionException;
+import org.junit.jupiter.api.extension.ParameterResolver;
+import org.testcontainers.shaded.com.google.common.collect.ImmutableList;
+
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+import reactor.core.scheduler.Schedulers;
+
+class ElasticSearchClusterExtension implements AfterAllCallback, BeforeAllCallback, AfterEachCallback, ParameterResolver {
+
+    static class ElasticSearchCluster {
+        DockerElasticSearch es1;
+        DockerElasticSearch es2;
+
+        ElasticSearchCluster(DockerElasticSearch es1, DockerElasticSearch es2) {
+            this.es1 = es1;
+            this.es2 = es2;
+        }
+
+        void start() {
+            doInParallel(es1::start, es2::start);
+        }
+
+        void cleanUp() {
+            doInParallel(() -> {
+                    if (es1.isRunning()) {
+                        es1.cleanUpData();
+                }},
+                () -> {
+                    if (es1.isRunning()) {
+                        es1.cleanUpData();
+                }});
+        }
+
+        void stop() {
+            doInParallel(es2::stop);
+        }
+
+        List<Host> getHosts() {
+            return ImmutableList.of(es1.getHttpHost(), es2.getHttpHost());
+        }
+
+        private void doInParallel(Runnable...runnables) {
+            Flux.fromStream(Stream.of(runnables)
+                    .map(Mono::fromRunnable))
+                .parallel(runnables.length)
+                .runOn(Schedulers.boundedElastic())
+                .flatMap(Function.identity())
+                .then()
+                .block();
+        }
+    }
+    
+    private final ElasticSearchCluster esCluster;
+
+    ElasticSearchClusterExtension(ElasticSearchCluster esCluster) {
+        this.esCluster = esCluster;
+    }
+
+    @Override
+    public void beforeAll(ExtensionContext extensionContext) throws Exception {
+        esCluster.start();
+    }
+
+    @Override
+    public void afterEach(ExtensionContext extensionContext) throws Exception {
+        esCluster.cleanUp();
+    }
+
+    @Override
+    public void afterAll(ExtensionContext extensionContext) throws Exception {
+        esCluster.stop();
+    }
+
+    @Override
+    public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
+        return parameterContext.getParameter().getType() == ElasticSearchCluster.class;
+    }
+
+    @Override
+    public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
+        return esCluster;
+    }
+}
\ No newline at end of file
diff --git a/backends-common/elasticsearch/src/test/resources/auth-es/NginxDockerfile b/backends-common/elasticsearch/src/test/resources/auth-es/NginxDockerfile
new file mode 100644
index 0000000..5a0f976
--- /dev/null
+++ b/backends-common/elasticsearch/src/test/resources/auth-es/NginxDockerfile
@@ -0,0 +1,5 @@
+FROM nginx:1.15.1
+
+COPY conf/nginx-conf/ /etc/nginx/conf.d/
+COPY conf/default.crt /etc/ssl/certs/default.crt
+COPY conf/default.key /etc/ssl/private/default.key
\ No newline at end of file
diff --git a/backends-common/elasticsearch/src/test/resources/auth-es/README.md b/backends-common/elasticsearch/src/test/resources/auth-es/README.md
new file mode 100644
index 0000000..b7d945e
--- /dev/null
+++ b/backends-common/elasticsearch/src/test/resources/auth-es/README.md
@@ -0,0 +1,30 @@
+## Resources explanation
+
+### nginx-conf
+
+Contains nginx configuration files:
+ - reverse_elasticsearch.conf: allow nginx to be the proxy connecting to ElasticSearch
+ - passwd: Nginx credentials file store, each record follow the format: `username:encrypted-password`
+
+### default.crt & default.key
+
+public (.crt) and private (.key) of the self signed SSL certification. It will be loaded by nginx
+
+### server.jks
+
+Once you use a http client connect to nginx by `https` protocol, 
+the default behavior of the client is rejecting the connection because 
+self signed SSL certification provided by nginx is not recognized by the 
+client. To deal with this problem, there are two ways to configure the client:
+
+ - Not recommended in production, ignore SSL Validation
+ - Configure the client to use local TrustStore file containing the .crt, 
+ then it should trust nginx.
+ 
+The `server.jks` is generated by the command
+```
+keytool -import -v -trustcacerts -file default.crt -keystore server.jks -keypass mypass -storepass mypass
+```
+
+With: 
+ - password: `mypass`
\ No newline at end of file
diff --git a/backends-common/elasticsearch/src/test/resources/auth-es/default.crt b/backends-common/elasticsearch/src/test/resources/auth-es/default.crt
new file mode 100644
index 0000000..d9aa6ca
--- /dev/null
+++ b/backends-common/elasticsearch/src/test/resources/auth-es/default.crt
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDBjCCAe4CCQDbp5K1cKRJgjANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB
+VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
+cyBQdHkgTHRkMB4XDTE4MDcwMjEyNDkxMloXDTE5MDcwMjEyNDkxMlowRTELMAkG
+A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0
+IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AMMgzSF3uTnjSPwX9i1FEhdpKCDWAfWdg/arMWI1wdNjaz5jwA0Y4hPXN14ArIkH
+ZCb9NPJZbUzcryeTvwEbZ8zqQ5+ghiGfGh9PFcz+RArOY2pPnIHOXVZaBIWxkzlF
+atdJodNhbkxt+gmPi5xFlwDqPMijnAOI4gLcxQPG7mWyRpoD8YUzmMNFTJr1xFAV
+XcJU+FJPP9zhOFRkGXnDupp8z9RYew+b39VGga6zHFGIP+iIMVJnEmW2/TQ1KE52
+b5B45bfGxlF7k003kIeaZsHbaIshdNMIz+w4bzywXNXyAfZccRGfraNXuSv0jAPS
+O+nF9yyAocnz3QXOsmSGz28CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAFRDXedF9
+hjuEmLjETBwhh5Zgg102GDJp58ZBkLE1IaT4mrbK90mhpzxsaxbuqOdu3PXJV4tc
+SEocxj5hk5ivVZiWk/j8YJmB8ZOUKdeOxc1tfratlonJ85AY+6m02+FhjUnWobmg
+HVBepFTJt1iaTgOpVf8YpbYW+L6+kWV9C2CtT3WUhxtllKjokbF+YVN7LnDlbynM
+80+aGm+rdg+TUusg+T/2FeVlDyBgbqagBcCQCQacWD2+zzL28XB3PwRE6oU/tKuu
+rbCsGZE0WH8Pc7p6J/alRr+foQiu7KKJKJ8pO1qdy716DlmPIDN23iZROIu1GKKl
+ZIKfyefPUcwHyw==
+-----END CERTIFICATE-----
\ No newline at end of file
diff --git a/backends-common/elasticsearch/src/test/resources/auth-es/default.key b/backends-common/elasticsearch/src/test/resources/auth-es/default.key
new file mode 100644
index 0000000..ebc29bb
--- /dev/null
+++ b/backends-common/elasticsearch/src/test/resources/auth-es/default.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAwyDNIXe5OeNI/Bf2LUUSF2koINYB9Z2D9qsxYjXB02NrPmPA
+DRjiE9c3XgCsiQdkJv008lltTNyvJ5O/ARtnzOpDn6CGIZ8aH08VzP5ECs5jak+c
+gc5dVloEhbGTOUVq10mh02FuTG36CY+LnEWXAOo8yKOcA4jiAtzFA8buZbJGmgPx
+hTOYw0VMmvXEUBVdwlT4Uk8/3OE4VGQZecO6mnzP1Fh7D5vf1UaBrrMcUYg/6Igx
+UmcSZbb9NDUoTnZvkHjlt8bGUXuTTTeQh5pmwdtoiyF00wjP7DhvPLBc1fIB9lxx
+EZ+to1e5K/SMA9I76cX3LIChyfPdBc6yZIbPbwIDAQABAoIBAQC+DHmeyjQPDK8u
+UcxE5UwsnxAlgysfZY59Ntn/dKpW0DNI7fDFEOJJPsm/ddqWECvcyavDC5SoUx0J
+6B4V3vJnpBe/JqLdpk/UBLwQD+qHt+MeTXH6/9rq2vwilwT0uAbKrv29mtzJ9ied
+HkF1MFZV3s7bAHdY/f5bmVkOR7g0NQ6QLuXYiLDSHpu/7dMVBNS9qMNL292cZbpi
+KJZUvyrK6jSOh9Dt3fmWVdjRp5nGd/Z0r32A8UdoWiQ3cXe9uwXVxz8+ZGkP4t44
+Ob+YcgHUEz6iI2o7nqWpNtPI+hBWH1YK/Szlay3rTZSKvkNG1Sdwm1UhoJqNFucC
+7ZWkH8GxAoGBAOSpP9lrB0sXCGwhD3xbAYCZsTgomSQ13X6/daKdN9fxpegK7v5r
+baojBoSvIKiKezHzMiL5IiEhESXEvXQigFNORdf9mFs9Z9ec4I/96dQNYM4d1QtM
+nz3dABt62po8ROCA4Y26ar+OmcJ2kv0RPuJCDGkrY1Is7SNTtGi+HW55AoGBANp1
+MJi3VHS9oEF8dslgLkZMZWPgcwJK2Y3wYIkatmxuVkWYdRFPqWWwlXUU17KH7eqm
+iEONLNyI7g/duFFTbz52MkeMpX6xarXddYkS2HMDUqSTgt3T+ULHVhTtlEEBXg6m
+5cx/eg8niJ6VH+vFtRcYrActLg751mjNgz8fmBMnAoGBAMwj4fHsIIXEWWuXlGi0
+IsI59EKr1BTE1isLKS11aN6sSS7BXB7dr/k97drVMrXldBjjArbAbtze1Z0/aNhe
+2OwGrEopiDSkvKl8z+sdh/0duHgroADHdj9Xp3nhE3qxJdi8lyHd9OFxoQpAq/es
+xtRenQ/jgXdizo9EcoM0f7gZAoGARw6ZSQNQyEwpxUM7zBKp2pnc3NjT7+nyy7Vl
+YRM8RRa6nxaQ9ZmIyxfd9WBbLKoEHDAg4IAaGH29mZGP83wFEjcV8anw5r3ErPUk
+1vo3R2nMRtXoWkkpqav29wW0FFTiiDeHRbYtOKKuUI7G/ESpu6J9yjPK6HohYKOA
+Tlbzez8CgYAFhpoeHO2X06pEsFeI6rMtc0rS0EHuVuqfjjyEMOyQZ8BsCWzDZBDW
+N9rxd0yz80H1Q33dwzrkiVu15e+JMNb5I80Ou0t+LQVYpvhtM89yKoLFk2HqL+eH
+wQJ/Fszj8fwdwx+k2DEve8MVHSx/w9CpwM7B2yGxcUFKi/JSM1rQEw==
+-----END RSA PRIVATE KEY-----
\ No newline at end of file
diff --git a/backends-common/elasticsearch/src/test/resources/auth-es/nginx-conf/passwd b/backends-common/elasticsearch/src/test/resources/auth-es/nginx-conf/passwd
new file mode 100644
index 0000000..c489f73
--- /dev/null
+++ b/backends-common/elasticsearch/src/test/resources/auth-es/nginx-conf/passwd
@@ -0,0 +1,2 @@
+# the default credential: elasticsearch:secret
+elasticsearch:$apr1$m5FvKpw7$EZ9UEUCilHyKTIqQ57nWG1
diff --git a/backends-common/elasticsearch/src/test/resources/auth-es/nginx-conf/reverse_elasticsearch.conf b/backends-common/elasticsearch/src/test/resources/auth-es/nginx-conf/reverse_elasticsearch.conf
new file mode 100644
index 0000000..77573cf
--- /dev/null
+++ b/backends-common/elasticsearch/src/test/resources/auth-es/nginx-conf/reverse_elasticsearch.conf
@@ -0,0 +1,12 @@
+server {
+    listen 9200 ssl;
+    ssl_certificate /etc/ssl/certs/default.crt;
+    ssl_certificate_key /etc/ssl/private/default.key;
+    server_name reverse_elasticsearch;
+    auth_basic "Restricted Area";
+    auth_basic_user_file /etc/nginx/conf.d/passwd;
+
+    location / {
+        proxy_pass http://elasticsearch:9200;
+    }
+}
diff --git a/backends-common/elasticsearch/src/test/resources/auth-es/server.jks b/backends-common/elasticsearch/src/test/resources/auth-es/server.jks
new file mode 100644
index 0000000..10ef996
Binary files /dev/null and b/backends-common/elasticsearch/src/test/resources/auth-es/server.jks differ
diff --git a/server/container/guice/cassandra-guice/src/test/java/org/apache/james/JamesWithNonCompatibleElasticSearchServerTest.java b/server/container/guice/cassandra-guice/src/test/java/org/apache/james/JamesWithNonCompatibleElasticSearchServerTest.java
index 3e16305..ebe9150 100644
--- a/server/container/guice/cassandra-guice/src/test/java/org/apache/james/JamesWithNonCompatibleElasticSearchServerTest.java
+++ b/server/container/guice/cassandra-guice/src/test/java/org/apache/james/JamesWithNonCompatibleElasticSearchServerTest.java
@@ -39,7 +39,7 @@ class JamesWithNonCompatibleElasticSearchServerTest {
 
     private static final int LIMIT_MAX_MESSAGES = 10;
 
-    static DockerElasticSearch dockerES2 = new DockerElasticSearch(Images.ELASTICSEARCH_2);
+    static DockerElasticSearch dockerES2 = new DockerElasticSearch.NoAuth(Images.ELASTICSEARCH_2);
 
     @RegisterExtension
     static JamesServerExtension testExtension = new JamesServerBuilder()
diff --git a/server/container/metrics/metrics-es-reporter/src/test/java/org/apache/james/metric/es/ES2ReporterTest.java b/server/container/metrics/metrics-es-reporter/src/test/java/org/apache/james/metric/es/ES2ReporterTest.java
index eb23804..1e09cf5 100644
--- a/server/container/metrics/metrics-es-reporter/src/test/java/org/apache/james/metric/es/ES2ReporterTest.java
+++ b/server/container/metrics/metrics-es-reporter/src/test/java/org/apache/james/metric/es/ES2ReporterTest.java
@@ -27,5 +27,5 @@ class ES2ReporterTest extends ESReporterContract {
 
     @RegisterExtension
     static DockerElasticSearchExtension testExtension = new DockerElasticSearchExtension(
-        new DockerElasticSearch(Images.ELASTICSEARCH_2));
+        new DockerElasticSearch.NoAuth(Images.ELASTICSEARCH_2));
 }
diff --git a/server/container/metrics/metrics-es-reporter/src/test/java/org/apache/james/metric/es/ES6ReporterTest.java b/server/container/metrics/metrics-es-reporter/src/test/java/org/apache/james/metric/es/ES6ReporterTest.java
index 0c201a4..ab7a9d4 100644
--- a/server/container/metrics/metrics-es-reporter/src/test/java/org/apache/james/metric/es/ES6ReporterTest.java
+++ b/server/container/metrics/metrics-es-reporter/src/test/java/org/apache/james/metric/es/ES6ReporterTest.java
@@ -25,5 +25,5 @@ import org.junit.jupiter.api.extension.RegisterExtension;
 class ES6ReporterTest extends ESReporterContract {
 
     @RegisterExtension
-    static DockerElasticSearchExtension testExtension = new DockerElasticSearchExtension(new DockerElasticSearch());
+    static DockerElasticSearchExtension testExtension = new DockerElasticSearchExtension(new DockerElasticSearch.NoAuth());
 }
diff --git a/server/testing/src/main/java/org/apache/james/util/docker/DockerContainer.java b/server/testing/src/main/java/org/apache/james/util/docker/DockerContainer.java
index 07904a1..73b9162 100644
--- a/server/testing/src/main/java/org/apache/james/util/docker/DockerContainer.java
+++ b/server/testing/src/main/java/org/apache/james/util/docker/DockerContainer.java
@@ -34,6 +34,7 @@ import org.slf4j.LoggerFactory;
 import org.testcontainers.DockerClientFactory;
 import org.testcontainers.containers.Container;
 import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.containers.Network;
 import org.testcontainers.containers.output.OutputFrame;
 import org.testcontainers.containers.wait.strategy.WaitStrategy;
 import org.testcontainers.images.builder.ImageFromDockerfile;
@@ -81,6 +82,16 @@ public class DockerContainer implements TestRule {
         return this;
     }
 
+    public DockerContainer withNetwork(Network network) {
+        container.withNetwork(network);
+        return this;
+    }
+
+    public DockerContainer withNetworkAliases(String... aliases) {
+        container.withNetworkAliases(aliases);
+        return this;
+    }
+
     public DockerContainer withLogConsumer(Consumer<OutputFrame> consumer) {
         container.withLogConsumer(consumer);
         return this;


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org