Skip to content

Commit

Permalink
Add withPassword(String) method to secure Elasticsearch
Browse files Browse the repository at this point in the history
Instead of providing env settings manually, we can simplify the usage of Elasticsearch in the context of TestContainers by just asking a password.
Behind the scene, we do provide the needed env settings.

We also remove the deprecated usage of default ctor.
  • Loading branch information
dadoonet committed Jul 4, 2020
1 parent 2f9305f commit 877aa4f
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 40 deletions.
23 changes: 5 additions & 18 deletions docs/modules/elasticsearch.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
This module helps running [elasticsearch](https://www.elastic.co/products/elasticsearch) using
Testcontainers.

Note that it's based on the [official Docker image](https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docker.html) provided by elastic.
Note that it's based on the [official Docker image](https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html) provided by elastic.

## Usage example

Expand All @@ -15,7 +15,7 @@ You can start an elasticsearch container instance from any Java application by u
<!--/codeinclude-->


Note that if you are still using the [TransportClient](https://www.elastic.co/guide/en/elasticsearch/client/java-api/7.5/transport-client.html)
Note that if you are still using the [TransportClient](https://www.elastic.co/guide/en/elasticsearch/client/java-api/6.3/transport-client.html)
(not recommended as it is deprecated), the default cluster name is set to `docker-cluster` so you need to change `cluster.name` setting
or set `client.transport.ignore_cluster_name` to `true`.

Expand All @@ -24,22 +24,9 @@ or set `client.transport.ignore_cluster_name` to `true`.
The default distribution of Elasticsearch comes with the basic license which contains security feature.
You can turn on security by providing a password:

```java
ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:7.5.2")
.withPassword("changeme");
```

In which case you can create the Client like this:

```java
// Do whatever you want with the rest client ...
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials("elastic", "changeme"));
RestClient restClient = RestClient.builder(HttpHost.create(container.getHttpHostAddress()))
.setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider))
.build();
Response response = restClient.performRequest(new Request("GET", "/"));
```
<!--codeinclude-->
[HttpClient](../../modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java) inside_block:httpClientSecuredContainer
<!--/codeinclude-->

## Choose your Elasticsearch license

Expand Down
2 changes: 1 addition & 1 deletion modules/elasticsearch/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ description = "TestContainers :: elasticsearch"
dependencies {
compile project(':testcontainers')
testCompile "org.elasticsearch.client:elasticsearch-rest-client:7.8.0"
testCompile "org.elasticsearch.client:transport:6.7.1"
testCompile "org.elasticsearch.client:transport:7.8.0"
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,11 @@
package org.testcontainers.elasticsearch;

import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows;
import static org.testcontainers.elasticsearch.ElasticsearchContainer.ELASTICSEARCH_DEFAULT_VERSION;

import java.io.IOException;

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.impl.client.BasicCredentialsProvider;
import org.apache.http.util.EntityUtils;
import org.elasticsearch.Version;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.Response;
Expand All @@ -27,12 +18,19 @@
import org.junit.After;
import org.junit.Test;

import java.io.IOException;

import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.rnorth.visibleassertions.VisibleAssertions.assertThrows;

public class ElasticsearchContainerTest {

/**
* Elasticsearch version which should be used for the Tests
*/
private static final String ELASTICSEARCH_VERSION = Version.CURRENT.toString();
private static final String ELASTICSEARCH_VERSION = "7.8.0";

/**
* Elasticsearch default username, when secured
Expand All @@ -44,11 +42,6 @@ public class ElasticsearchContainerTest {
*/
private static final String ELASTICSEARCH_PASSWORD = "changeme";

/**
* Elasticsearch older version. We want to test the N-1 major version.
*/
private static final String ELASTICSEARCH_OLDER_VERSION = "6.8.6";

private RestClient client = null;
private RestClient anonymousClient = null;

Expand All @@ -67,7 +60,7 @@ public void stopRestClient() throws IOException {
@Test
public void elasticsearchDefaultTest() throws IOException {
// Create the elasticsearch container.
try (ElasticsearchContainer container = new ElasticsearchContainer()
try (ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:" + ELASTICSEARCH_VERSION)
.withEnv("foo", "bar") // dummy env for compiler checking correct generics usage
) {
// Start the container. This step might take some time...
Expand All @@ -76,7 +69,7 @@ public void elasticsearchDefaultTest() throws IOException {
// Do whatever you want with the rest client ...
Response response = getClient(container).performRequest(new Request("GET", "/"));
assertThat(response.getStatusLine().getStatusCode(), is(200));
assertThat(EntityUtils.toString(response.getEntity()), containsString(ELASTICSEARCH_DEFAULT_VERSION));
assertThat(EntityUtils.toString(response.getEntity()), containsString(ELASTICSEARCH_VERSION));

// The default image is running with the features under Elastic License
response = getClient(container).performRequest(new Request("GET", "/_xpack/"));
Expand All @@ -88,7 +81,8 @@ public void elasticsearchDefaultTest() throws IOException {

@Test
public void elasticsearchSecuredTest() throws IOException {
try (ElasticsearchContainer container = new ElasticsearchContainer().withPassword(ELASTICSEARCH_PASSWORD)) {
try (ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:" + ELASTICSEARCH_VERSION)
.withPassword(ELASTICSEARCH_PASSWORD)) {
container.start();

// The cluster should be secured so it must fail when we try to access / without credentials
Expand All @@ -99,7 +93,7 @@ public void elasticsearchSecuredTest() throws IOException {
// But it should work when we try to access / with the proper login and password
Response response = getClient(container).performRequest(new Request("GET", "/"));
assertThat(response.getStatusLine().getStatusCode(), is(200));
assertThat(EntityUtils.toString(response.getEntity()), containsString(ELASTICSEARCH_DEFAULT_VERSION));
assertThat(EntityUtils.toString(response.getEntity()), containsString(ELASTICSEARCH_VERSION));
}
}

Expand Down Expand Up @@ -131,11 +125,37 @@ public void elasticsearchOssImage() throws IOException {
}
}

@Test
public void restClientSecuredClusterHealth() throws IOException {
// httpClientSecuredContainer {
// Create the elasticsearch container.
try (ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:" + ELASTICSEARCH_VERSION)
// With a password
.withPassword(ELASTICSEARCH_PASSWORD)) {
// Start the container. This step might take some time...
container.start();

final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials(ELASTICSEARCH_USERNAME, ELASTICSEARCH_PASSWORD));

RestClient client = RestClient.builder(HttpHost.create(container.getHttpHostAddress()))
.setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider))
.build();

Response response = client.performRequest(new Request("GET", "/_cluster/health"));
assertThat(response.getStatusLine().getStatusCode(), is(200));
assertThat(EntityUtils.toString(response.getEntity()), containsString("cluster_name"));
// httpClientSecuredContainer {{
}
// }
}

@Test
public void restClientClusterHealth() throws IOException {
// httpClientContainer {
// Create the elasticsearch container.
try (ElasticsearchContainer container = new ElasticsearchContainer()) {
try (ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:" + ELASTICSEARCH_VERSION)) {
// Start the container. This step might take some time...
container.start();

Expand All @@ -161,7 +181,7 @@ public void restClientClusterHealth() throws IOException {
public void transportClientClusterHealth() {
// transportClientContainer {
// Create the elasticsearch container.
try (ElasticsearchContainer container = new ElasticsearchContainer()) {
try (ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:" + ELASTICSEARCH_VERSION)) {
// Start the container. This step might take some time...
container.start();

Expand Down

0 comments on commit 877aa4f

Please sign in to comment.