Skip to content

Commit

Permalink
Add a test for secured cluster
Browse files Browse the repository at this point in the history
This can be now activated for free with the default basic license.
  • Loading branch information
dadoonet committed Jul 7, 2020
1 parent 923472f commit a605c74
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 14 deletions.
19 changes: 17 additions & 2 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/6.3/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,10 +15,25 @@ 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/6.3/transport-client.html)
Note that if you are still using the [TransportClient](https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/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`.

## Secure your Elasticsearch cluster

The default distribution of Elasticsearch comes with the basic license which contains security feature.
You can turn on security by providing some extra environment settings:

```java
ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:7.5.2")
.withEnv("ELASTIC_PASSWORD", "changeme")
.withEnv("xpack.security.enabled", "true");
```

<!--codeinclude-->
[HttpClient](../../modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java) inside_block:httpClientSecuredContainer
<!--/codeinclude-->

## Choose your Elasticsearch license

If you prefer to start a Docker image with the pure OSS version (which means with no security in older versions or
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
Expand Up @@ -29,20 +29,23 @@ public class ElasticsearchContainer extends GenericContainer<ElasticsearchContai
/**
* Elasticsearch Docker base URL
*/
@Deprecated
private static final String ELASTICSEARCH_DEFAULT_IMAGE = "docker.elastic.co/elasticsearch/elasticsearch";

/**
* Elasticsearch Default version
*/
protected static final String ELASTICSEARCH_DEFAULT_VERSION = "6.4.1";
@Deprecated
protected static final String ELASTICSEARCH_DEFAULT_VERSION = "7.8.0";

@Deprecated
public ElasticsearchContainer() {
this(ELASTICSEARCH_DEFAULT_IMAGE + ":" + ELASTICSEARCH_DEFAULT_VERSION);
this("docker.elastic.co/elasticsearch/elasticsearch:7.8.0");
}

/**
* Create an Elasticsearch Container by passing the full docker image name
* @param dockerImageName Full docker image name, like: docker.elastic.co/elasticsearch/elasticsearch:6.4.1
* @param dockerImageName Full docker image name, like: docker.elastic.co/elasticsearch/elasticsearch:7.8.0
*/
public ElasticsearchContainer(String dockerImageName) {
super(dockerImageName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
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 @@ -32,32 +31,37 @@ 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 with a license > basic
* Elasticsearch default username, when secured
*/
private static final String ELASTICSEARCH_USERNAME = "elastic";

/**
* Elasticsearch 5.x default password. In 6.x images, there's no security by default as shipped with a basic license.
* From 6.8, we can optionally activate security with a default password.
*/
private static final String ELASTICSEARCH_PASSWORD = "changeme";

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

@After
public void stopRestClient() throws IOException {
if (client != null) {
client.close();
client = null;
}
if (anonymousClient != null) {
anonymousClient.close();
anonymousClient = null;
}
}

@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 @@ -66,7 +70,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 @@ -76,6 +80,26 @@ public void elasticsearchDefaultTest() throws IOException {
}
}

@Test
public void elasticsearchSecuredTest() throws IOException {
try (ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:" + ELASTICSEARCH_VERSION)
.withEnv("ELASTIC_PASSWORD", ELASTICSEARCH_PASSWORD)
.withEnv("xpack.security.enabled", "true")
) {
container.start();

// The cluster should be secured so it must fail when we try to access / without credentials
assertThrows("We should not be able to access / URI with an anonymous client.",
ResponseException.class,
() -> getAnonymousClient(container).performRequest(new Request("GET", "/")));

// 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_VERSION));
}
}

@Test
public void elasticsearchVersion() throws IOException {
try (ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:" + ELASTICSEARCH_VERSION)) {
Expand Down Expand Up @@ -104,11 +128,39 @@ 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
.withEnv("ELASTIC_PASSWORD", ELASTICSEARCH_PASSWORD)
.withEnv("xpack.security.enabled", "true")) {
// Start the container. This step might take some time...
container.start();

// Create the secured client.
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials(ELASTICSEARCH_USERNAME, ELASTICSEARCH_PASSWORD));

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 @@ -134,7 +186,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 Expand Up @@ -168,4 +220,11 @@ private RestClient getClient(ElasticsearchContainer container) {
return client;
}

private RestClient getAnonymousClient(ElasticsearchContainer container) {
if (anonymousClient == null) {
anonymousClient = RestClient.builder(HttpHost.create(container.getHttpHostAddress())).build();
}

return anonymousClient;
}
}

0 comments on commit a605c74

Please sign in to comment.