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 2e87e12dbce48737c21ad29138e445ceb1b8a35b Author: Tran Tien Duc <[email protected]> AuthorDate: Wed Nov 13 18:20:06 2019 +0700 JAMES-2905 One more option about HostNameVerifier --- .../apache/james/backends/es/ClientProvider.java | 29 ++++- .../backends/es/ElasticSearchConfiguration.java | 144 ++++++++++++++++----- ...iderImplConnectionAuthESIgnoreSSLCheckTest.java | 7 +- ...ImplConnectionAuthESOverrideTrustStoreTest.java | 10 +- .../es/ElasticSearchConfigurationTest.java | 118 +++++++++++++---- .../destination/conf/elasticsearch.properties | 6 + .../destination/conf/elasticsearch.properties | 6 + .../destination/conf/elasticsearch.properties | 6 + .../destination/conf/elasticsearch.properties | 6 + src/site/xdoc/server/config-elasticsearch.xml | 15 +++ 10 files changed, 282 insertions(+), 65 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 50a51e7..1ff14cd 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 @@ -38,13 +38,15 @@ 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.DefaultHostnameVerifier; 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.apache.james.backends.es.ElasticSearchConfiguration.SSLConfiguration.HostNameVerifier; +import org.apache.james.backends.es.ElasticSearchConfiguration.SSLConfiguration.SSLTrustStore; +import org.apache.james.backends.es.ElasticSearchConfiguration.SSLConfiguration.SSLValidationStrategy; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestHighLevelClient; import org.slf4j.Logger; @@ -60,7 +62,7 @@ public class ClientProvider implements Provider<RestHighLevelClient> { private static class HttpAsyncClientConfigurer { private static final TrustStrategy TRUST_ALL = (x509Certificates, authType) -> true; - private static final HostnameVerifier ACCEPT_ANY_HOST = (hostname, sslSession) -> true; + private static final HostnameVerifier ACCEPT_ANY_HOSTNAME = (hostname, sslSession) -> true; private final ElasticSearchConfiguration configuration; @@ -94,7 +96,7 @@ public class ClientProvider implements Provider<RestHighLevelClient> { try { builder .setSSLContext(sslContext()) - .setSSLHostnameVerifier(ACCEPT_ANY_HOST); + .setSSLHostnameVerifier(hostnameVerifier()); } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException | CertificateException | IOException e) { throw new RuntimeException("Cannot set SSL options to the builder", e); } @@ -105,7 +107,7 @@ public class ClientProvider implements Provider<RestHighLevelClient> { SSLContextBuilder sslContextBuilder = new SSLContextBuilder(); - SSLValidationStrategy strategy = configuration.getSslTrustConfiguration() + SSLValidationStrategy strategy = configuration.getSslConfiguration() .getStrategy(); switch (strategy) { @@ -123,10 +125,25 @@ public class ClientProvider implements Provider<RestHighLevelClient> { } } + private HostnameVerifier hostnameVerifier() { + HostNameVerifier hostnameVerifier = configuration.getSslConfiguration() + .getHostNameVerifier(); + + switch (hostnameVerifier) { + case DEFAULT: + return new DefaultHostnameVerifier(); + case ACCEPT_ANY_HOSTNAME: + return ACCEPT_ANY_HOSTNAME; + default: + throw new NotImplementedException( + String.format("unrecognized HostNameVerifier '%s'", hostnameVerifier.name())); + } + } + private SSLContextBuilder applyTrustStore(SSLContextBuilder sslContextBuilder) throws CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException { - SSLTrustStore trustStore = configuration.getSslTrustConfiguration() + SSLTrustStore trustStore = configuration.getSslConfiguration() .getTrustStore() .orElseThrow(() -> new IllegalStateException("SSLTrustStore cannot to be empty")); diff --git a/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/ElasticSearchConfiguration.java b/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/ElasticSearchConfiguration.java index 47681a5..16727ea 100644 --- a/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/ElasticSearchConfiguration.java +++ b/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/ElasticSearchConfiguration.java @@ -19,7 +19,7 @@ package org.apache.james.backends.es; -import static org.apache.james.backends.es.ElasticSearchConfiguration.SSLTrustConfiguration.SSLValidationStrategy.OVERRIDE; +import static org.apache.james.backends.es.ElasticSearchConfiguration.SSLConfiguration.SSLValidationStrategy.OVERRIDE; import java.io.File; import java.nio.file.Files; @@ -35,8 +35,9 @@ import java.util.stream.Stream; import org.apache.commons.configuration2.Configuration; import org.apache.commons.configuration2.ex.ConfigurationException; -import org.apache.james.backends.es.ElasticSearchConfiguration.SSLTrustConfiguration.SSLTrustStore; -import org.apache.james.backends.es.ElasticSearchConfiguration.SSLTrustConfiguration.SSLValidationStrategy; +import org.apache.james.backends.es.ElasticSearchConfiguration.SSLConfiguration.HostNameVerifier; +import org.apache.james.backends.es.ElasticSearchConfiguration.SSLConfiguration.SSLTrustStore; +import org.apache.james.backends.es.ElasticSearchConfiguration.SSLConfiguration.SSLValidationStrategy; import org.apache.james.util.Host; import com.github.steveash.guavate.Guavate; @@ -110,7 +111,7 @@ public class ElasticSearchConfiguration { } } - public static class SSLTrustConfiguration { + public static class SSLConfiguration { public enum SSLValidationStrategy { DEFAULT, @@ -128,6 +129,21 @@ public class ElasticSearchConfiguration { } } + public enum HostNameVerifier { + DEFAULT, + ACCEPT_ANY_HOSTNAME; + + static HostNameVerifier from(String rawValue) { + Preconditions.checkNotNull(rawValue); + + return Stream.of(values()) + .filter(verifier -> verifier.name().equalsIgnoreCase(rawValue)) + .findAny() + .orElseThrow(() -> new IllegalArgumentException(String.format("invalid HostNameVerifier '%s'", rawValue))); + + } + } + public static class SSLTrustStore { public static SSLTrustStore of(String filePath, String password) { @@ -174,28 +190,79 @@ public class ElasticSearchConfiguration { } } - static SSLTrustConfiguration defaultBehavior() { - return new SSLTrustConfiguration(SSLValidationStrategy.DEFAULT, Optional.empty()); + static class Builder { + + interface RequireSSLStrategyTrustStore { + RequireHostNameVerifier sslStrategy(SSLValidationStrategy strategy, Optional<SSLTrustStore> trustStore); + + default RequireHostNameVerifier strategyIgnore() { + return sslStrategy(SSLValidationStrategy.IGNORE, Optional.empty()); + } + + default RequireHostNameVerifier strategyOverride(SSLTrustStore trustStore) { + return sslStrategy(SSLValidationStrategy.OVERRIDE, Optional.of(trustStore)); + } + + default RequireHostNameVerifier strategyDefault() { + return sslStrategy(SSLValidationStrategy.DEFAULT, Optional.empty()); + } + } + + interface RequireHostNameVerifier { + ReadyToBuild hostNameVerifier(HostNameVerifier hostNameVerifier); + + default ReadyToBuild acceptAnyHostNameVerifier() { + return hostNameVerifier(HostNameVerifier.ACCEPT_ANY_HOSTNAME); + } + + default ReadyToBuild defaultHostNameVerifier() { + return hostNameVerifier(HostNameVerifier.DEFAULT); + } + } + + static class ReadyToBuild { + private final SSLValidationStrategy sslValidationStrategy; + private final HostNameVerifier hostNameVerifier; + private Optional<SSLTrustStore> sslTrustStore; + + private ReadyToBuild(SSLValidationStrategy sslValidationStrategy, HostNameVerifier hostNameVerifier, Optional<SSLTrustStore> sslTrustStore) { + this.sslValidationStrategy = sslValidationStrategy; + this.hostNameVerifier = hostNameVerifier; + this.sslTrustStore = sslTrustStore; + } + + public ReadyToBuild sslTrustStore(SSLTrustStore sslTrustStore) { + this.sslTrustStore = Optional.of(sslTrustStore); + return this; + } + + public SSLConfiguration build() { + return new SSLConfiguration(sslValidationStrategy, hostNameVerifier, sslTrustStore); + } + } } - static SSLTrustConfiguration ignore() { - return new SSLTrustConfiguration(SSLValidationStrategy.IGNORE, Optional.empty()); + static SSLConfiguration defaultBehavior() { + return new SSLConfiguration(SSLValidationStrategy.DEFAULT, HostNameVerifier.DEFAULT, Optional.empty()); } - static SSLTrustConfiguration override(SSLTrustStore sslTrustStore) { - return new SSLTrustConfiguration(OVERRIDE, Optional.of(sslTrustStore)); + static Builder.RequireSSLStrategyTrustStore builder() { + return (strategy, trustStore) -> hostNameVerifier -> new Builder.ReadyToBuild(strategy, hostNameVerifier, trustStore); } private final SSLValidationStrategy strategy; + private final HostNameVerifier hostNameVerifier; private final Optional<SSLTrustStore> trustStore; - private SSLTrustConfiguration(SSLValidationStrategy strategy, Optional<SSLTrustStore> trustStore) { + private SSLConfiguration(SSLValidationStrategy strategy, HostNameVerifier hostNameVerifier, Optional<SSLTrustStore> trustStore) { Preconditions.checkNotNull(strategy); Preconditions.checkNotNull(trustStore); + Preconditions.checkNotNull(hostNameVerifier); Preconditions.checkArgument(strategy != OVERRIDE || trustStore.isPresent(), OVERRIDE.name() + " strategy requires trustStore to be present"); this.strategy = strategy; this.trustStore = trustStore; + this.hostNameVerifier = hostNameVerifier; } public SSLValidationStrategy getStrategy() { @@ -206,20 +273,25 @@ public class ElasticSearchConfiguration { return trustStore; } + public HostNameVerifier getHostNameVerifier() { + return hostNameVerifier; + } + @Override public final boolean equals(Object o) { - if (o instanceof SSLTrustConfiguration) { - SSLTrustConfiguration that = (SSLTrustConfiguration) o; + if (o instanceof SSLConfiguration) { + SSLConfiguration that = (SSLConfiguration) o; return Objects.equals(this.strategy, that.strategy) - && Objects.equals(this.trustStore, that.trustStore); + && Objects.equals(this.trustStore, that.trustStore) + && Objects.equals(this.hostNameVerifier, that.hostNameVerifier); } return false; } @Override public final int hashCode() { - return Objects.hash(strategy, trustStore); + return Objects.hash(strategy, trustStore, hostNameVerifier); } } @@ -234,7 +306,7 @@ public class ElasticSearchConfiguration { private Optional<Duration> requestTimeout; private Optional<HostScheme> hostScheme; private Optional<Credential> credential; - private Optional<SSLTrustConfiguration> sslTrustConfiguration; + private Optional<SSLConfiguration> sslTrustConfiguration; public Builder() { hosts = ImmutableList.builder(); @@ -302,12 +374,12 @@ public class ElasticSearchConfiguration { return this; } - public Builder sslTrustConfiguration(SSLTrustConfiguration sslTrustConfiguration) { - this.sslTrustConfiguration = Optional.of(sslTrustConfiguration); + public Builder sslTrustConfiguration(SSLConfiguration sslConfiguration) { + this.sslTrustConfiguration = Optional.of(sslConfiguration); return this; } - public Builder sslTrustConfiguration(Optional<SSLTrustConfiguration> sslTrustStore) { + public Builder sslTrustConfiguration(Optional<SSLConfiguration> sslTrustStore) { this.sslTrustConfiguration = sslTrustStore; return this; } @@ -338,6 +410,7 @@ public class ElasticSearchConfiguration { public static final String ELASTICSEARCH_PORT = "elasticsearch.port"; public static final String ELASTICSEARCH_HOST_SCHEME = "elasticsearch.hostScheme"; public static final String ELASTICSEARCH_HTTPS_SSL_VALIDATION_STRATEGY = "elasticsearch.hostScheme.https.sslValidationStrategy"; + public static final String ELASTICSEARCH_HTTPS_HOSTNAME_VERIFIER = "elasticsearch.hostScheme.https.hostNameVerifier"; public static final String ELASTICSEARCH_HTTPS_TRUST_STORE_PATH = "elasticsearch.hostScheme.https.trustStorePath"; public static final String ELASTICSEARCH_HTTPS_TRUST_STORE_PASSWORD = "elasticsearch.hostScheme.https.trustStorePassword"; public static final String ELASTICSEARCH_USER = "elasticsearch.user"; @@ -358,7 +431,7 @@ public class ElasticSearchConfiguration { public static final String LOCALHOST = "127.0.0.1"; public static final Optional<Integer> DEFAULT_PORT_AS_OPTIONAL = Optional.of(DEFAULT_PORT); public static final HostScheme DEFAULT_SCHEME = HostScheme.HTTP; - public static final SSLTrustConfiguration DEFAULT_SSL_TRUST_CONFIGURATION = SSLTrustConfiguration.defaultBehavior(); + public static final SSLConfiguration DEFAULT_SSL_TRUST_CONFIGURATION = SSLConfiguration.defaultBehavior(); public static final ElasticSearchConfiguration DEFAULT_CONFIGURATION = builder() .addHost(Host.from(LOCALHOST, DEFAULT_PORT)) @@ -378,10 +451,21 @@ public class ElasticSearchConfiguration { .build(); } - private static Optional<SSLTrustConfiguration> sslTrustConfiguration(Configuration configuration) { - return Optional.ofNullable(configuration.getString(ELASTICSEARCH_HTTPS_SSL_VALIDATION_STRATEGY)) + private static SSLConfiguration sslTrustConfiguration(Configuration configuration) { + SSLValidationStrategy sslStrategy = Optional + .ofNullable(configuration.getString(ELASTICSEARCH_HTTPS_SSL_VALIDATION_STRATEGY)) .map(SSLValidationStrategy::from) - .map(strategy -> new SSLTrustConfiguration(strategy, getSSLTrustStore(configuration))); + .orElse(SSLValidationStrategy.DEFAULT); + + HostNameVerifier hostNameVerifier = Optional + .ofNullable(configuration.getString(ELASTICSEARCH_HTTPS_HOSTNAME_VERIFIER)) + .map(HostNameVerifier::from) + .orElse(HostNameVerifier.DEFAULT); + + return SSLConfiguration.builder() + .sslStrategy(sslStrategy, getSSLTrustStore(configuration)) + .hostNameVerifier(hostNameVerifier) + .build(); } private static Optional<SSLTrustStore> getSSLTrustStore(Configuration configuration) { @@ -455,10 +539,10 @@ public class ElasticSearchConfiguration { private final Duration requestTimeout; private final HostScheme hostScheme; private final Optional<Credential> credential; - private final SSLTrustConfiguration sslTrustConfiguration; + private final SSLConfiguration sslConfiguration; private ElasticSearchConfiguration(ImmutableList<Host> hosts, int nbShards, int nbReplica, int waitForActiveShards, int minDelay, int maxRetries, Duration requestTimeout, - HostScheme hostScheme, Optional<Credential> credential, SSLTrustConfiguration sslTrustConfiguration) { + HostScheme hostScheme, Optional<Credential> credential, SSLConfiguration sslConfiguration) { this.hosts = hosts; this.nbShards = nbShards; this.nbReplica = nbReplica; @@ -468,7 +552,7 @@ public class ElasticSearchConfiguration { this.requestTimeout = requestTimeout; this.hostScheme = hostScheme; this.credential = credential; - this.sslTrustConfiguration = sslTrustConfiguration; + this.sslConfiguration = sslConfiguration; } public ImmutableList<Host> getHosts() { @@ -507,8 +591,8 @@ public class ElasticSearchConfiguration { return credential; } - public SSLTrustConfiguration getSslTrustConfiguration() { - return sslTrustConfiguration; + public SSLConfiguration getSslConfiguration() { + return sslConfiguration; } @Override @@ -525,7 +609,7 @@ public class ElasticSearchConfiguration { && Objects.equals(this.requestTimeout, that.requestTimeout) && Objects.equals(this.hostScheme, that.hostScheme) && Objects.equals(this.credential, that.credential) - && Objects.equals(this.sslTrustConfiguration, that.sslTrustConfiguration); + && Objects.equals(this.sslConfiguration, that.sslConfiguration); } return false; } @@ -533,6 +617,6 @@ public class ElasticSearchConfiguration { @Override public final int hashCode() { return Objects.hash(hosts, nbShards, nbReplica, waitForActiveShards, minDelay, maxRetries, requestTimeout, - hostScheme, credential, sslTrustConfiguration); + hostScheme, credential, sslConfiguration); } } diff --git a/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/ClientProviderImplConnectionAuthESIgnoreSSLCheckTest.java b/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/ClientProviderImplConnectionAuthESIgnoreSSLCheckTest.java index 1de1996..a97c6a3 100644 --- a/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/ClientProviderImplConnectionAuthESIgnoreSSLCheckTest.java +++ b/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/ClientProviderImplConnectionAuthESIgnoreSSLCheckTest.java @@ -24,7 +24,7 @@ import static org.apache.james.backends.es.ElasticSearchClusterExtension.Elastic import java.util.Optional; import org.apache.james.backends.es.ElasticSearchConfiguration.HostScheme; -import org.apache.james.backends.es.ElasticSearchConfiguration.SSLTrustConfiguration; +import org.apache.james.backends.es.ElasticSearchConfiguration.SSLConfiguration; import org.junit.jupiter.api.extension.RegisterExtension; class ClientProviderImplConnectionAuthESIgnoreSSLCheckTest implements ClientProviderImplConnectionContract { @@ -39,6 +39,9 @@ class ClientProviderImplConnectionAuthESIgnoreSSLCheckTest implements ClientProv return ElasticSearchConfiguration.builder() .credential(Optional.of(DockerElasticSearch.WithAuth.DEFAULT_CREDENTIAL)) .hostScheme(Optional.of(HostScheme.HTTPS)) - .sslTrustConfiguration(SSLTrustConfiguration.ignore()); + .sslTrustConfiguration(SSLConfiguration.builder() + .strategyIgnore() + .acceptAnyHostNameVerifier() + .build()); } } diff --git a/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/ClientProviderImplConnectionAuthESOverrideTrustStoreTest.java b/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/ClientProviderImplConnectionAuthESOverrideTrustStoreTest.java index 5b92cf7..7493681 100644 --- a/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/ClientProviderImplConnectionAuthESOverrideTrustStoreTest.java +++ b/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/ClientProviderImplConnectionAuthESOverrideTrustStoreTest.java @@ -21,8 +21,8 @@ package org.apache.james.backends.es; import java.util.Optional; -import org.apache.james.backends.es.ElasticSearchConfiguration.SSLTrustConfiguration; -import org.apache.james.backends.es.ElasticSearchConfiguration.SSLTrustConfiguration.SSLTrustStore; +import org.apache.james.backends.es.ElasticSearchConfiguration.SSLConfiguration; +import org.apache.james.backends.es.ElasticSearchConfiguration.SSLConfiguration.SSLTrustStore; import org.junit.jupiter.api.extension.RegisterExtension; public class ClientProviderImplConnectionAuthESOverrideTrustStoreTest implements ClientProviderImplConnectionContract { @@ -40,7 +40,9 @@ public class ClientProviderImplConnectionAuthESOverrideTrustStoreTest implements return ElasticSearchConfiguration.builder() .credential(Optional.of(DockerElasticSearch.WithAuth.DEFAULT_CREDENTIAL)) .hostScheme(Optional.of(ElasticSearchConfiguration.HostScheme.HTTPS)) - .sslTrustConfiguration(SSLTrustConfiguration.override( - SSLTrustStore.of(TRUST_STORE_FILE_PATH, TRUST_STORE_PASSWORD))); + .sslTrustConfiguration(SSLConfiguration.builder() + .strategyOverride(SSLTrustStore.of(TRUST_STORE_FILE_PATH, TRUST_STORE_PASSWORD)) + .acceptAnyHostNameVerifier() + .build()); } } \ No newline at end of file diff --git a/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/ElasticSearchConfigurationTest.java b/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/ElasticSearchConfigurationTest.java index cf50942..35bf3f4 100644 --- a/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/ElasticSearchConfigurationTest.java +++ b/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/ElasticSearchConfigurationTest.java @@ -29,8 +29,8 @@ import org.apache.commons.configuration2.convert.DefaultListDelimiterHandler; import org.apache.commons.configuration2.ex.ConfigurationException; import org.apache.james.backends.es.ElasticSearchConfiguration.Credential; import org.apache.james.backends.es.ElasticSearchConfiguration.HostScheme; -import org.apache.james.backends.es.ElasticSearchConfiguration.SSLTrustConfiguration; -import org.apache.james.backends.es.ElasticSearchConfiguration.SSLTrustConfiguration.SSLTrustStore; +import org.apache.james.backends.es.ElasticSearchConfiguration.SSLConfiguration; +import org.apache.james.backends.es.ElasticSearchConfiguration.SSLConfiguration.SSLTrustStore; import org.apache.james.util.Host; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -62,7 +62,7 @@ class ElasticSearchConfigurationTest { } @Nested - class SSLTrustConfigurationTest { + class SSLConfigurationTest { @Test void sslTrustStoreShouldMatchBeanContact() { @@ -72,45 +72,112 @@ class ElasticSearchConfigurationTest { @Test void shouldMatchBeanContact() { - EqualsVerifier.forClass(SSLTrustConfiguration.class) + EqualsVerifier.forClass(SSLConfiguration.class) .verify(); } + @Test + void getSSLConfigurationShouldReturnDefaultValueWhenEmpty() throws Exception { + PropertiesConfiguration configuration = new PropertiesConfiguration(); + configuration.addProperty("elasticsearch.hosts", "127.0.0.1"); + + assertThat(ElasticSearchConfiguration.fromProperties(configuration) + .getSslConfiguration()) + .isEqualTo(SSLConfiguration.defaultBehavior()); + } + + @Test + void getSSLConfigurationShouldReturnConfiguredValue() throws Exception { + PropertiesConfiguration configuration = new PropertiesConfiguration(); + configuration.addProperty("elasticsearch.hosts", "127.0.0.1"); + + String trustStorePath = "src/test/resources/auth-es/server.jks"; + String trustStorePassword = "secret"; + + configuration.addProperty("elasticsearch.hostScheme.https.sslValidationStrategy", "override"); + configuration.addProperty("elasticsearch.hostScheme.https.trustStorePath", trustStorePath); + configuration.addProperty("elasticsearch.hostScheme.https.trustStorePassword", trustStorePassword); + configuration.addProperty("elasticsearch.hostScheme.https.hostNameVerifier", "default"); + + assertThat(ElasticSearchConfiguration.fromProperties(configuration) + .getSslConfiguration()) + .isEqualTo(SSLConfiguration.builder() + .strategyOverride(SSLTrustStore.of(trustStorePath, trustStorePassword)) + .defaultHostNameVerifier() + .build()); + } + @Nested class WithSSLValidationStrategy { @Test - void getSSLConfigurationShouldReturnDefaultValueWhenEmpty() throws Exception { + void getSSLConfigurationShouldAcceptCaseInsensitiveStrategy() throws Exception { PropertiesConfiguration configuration = new PropertiesConfiguration(); configuration.addProperty("elasticsearch.hosts", "127.0.0.1"); + configuration.addProperty("elasticsearch.hostScheme.https.sslValidationStrategy", "DEfault"); + assertThat(ElasticSearchConfiguration.fromProperties(configuration) - .getSslTrustConfiguration()) - .isEqualTo(SSLTrustConfiguration.defaultBehavior()); + .getSslConfiguration()) + .isEqualTo(SSLConfiguration.defaultBehavior()); } @Test - void getSSLConfigurationShouldAcceptCaseInsensitiveStrategy() throws Exception { + void fromPropertiesShouldThrowWhenInvalidStrategy() throws Exception { PropertiesConfiguration configuration = new PropertiesConfiguration(); configuration.addProperty("elasticsearch.hosts", "127.0.0.1"); - configuration.addProperty("elasticsearch.hostScheme.https.sslValidationStrategy", "DEfault"); + configuration.addProperty("elasticsearch.hostScheme.https.sslValidationStrategy", "invalid"); + + assertThatThrownBy(() -> ElasticSearchConfiguration.fromProperties(configuration)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("invalid strategy 'invalid'"); + } + } + + @Nested + class WithHostNameVerifier { + + @Test + void getSSLConfigurationShouldReturnConfiguredValue() throws Exception { + PropertiesConfiguration configuration = new PropertiesConfiguration(); + configuration.addProperty("elasticsearch.hosts", "127.0.0.1"); + + configuration.addProperty("elasticsearch.hostScheme.https.hostNameVerifier", "DEFAULT"); assertThat(ElasticSearchConfiguration.fromProperties(configuration) - .getSslTrustConfiguration()) - .isEqualTo(SSLTrustConfiguration.defaultBehavior()); + .getSslConfiguration()) + .isEqualTo(SSLConfiguration.builder() + .strategyDefault() + .defaultHostNameVerifier() + .build()); } @Test - void fromPropertiesShouldThrowWhenInvalidStrategy() throws Exception { + void getSSLConfigurationShouldAcceptCaseInsensitiveVerifier() throws Exception { PropertiesConfiguration configuration = new PropertiesConfiguration(); configuration.addProperty("elasticsearch.hosts", "127.0.0.1"); - configuration.addProperty("elasticsearch.hostScheme.https.sslValidationStrategy", "invalid"); + configuration.addProperty("elasticsearch.hostScheme.https.hostNameVerifier", "Accept_Any_Hostname"); + + assertThat(ElasticSearchConfiguration.fromProperties(configuration) + .getSslConfiguration()) + .isEqualTo(SSLConfiguration.builder() + .strategyDefault() + .acceptAnyHostNameVerifier() + .build()); + } + + @Test + void fromPropertiesShouldThrowWhenInvalidVerifier() throws Exception { + PropertiesConfiguration configuration = new PropertiesConfiguration(); + configuration.addProperty("elasticsearch.hosts", "127.0.0.1"); + + configuration.addProperty("elasticsearch.hostScheme.https.hostNameVerifier", "invalid"); assertThatThrownBy(() -> ElasticSearchConfiguration.fromProperties(configuration)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("invalid strategy 'invalid'"); + .hasMessage("invalid HostNameVerifier 'invalid'"); } } @@ -125,8 +192,8 @@ class ElasticSearchConfigurationTest { configuration.addProperty("elasticsearch.hostScheme.https.sslValidationStrategy", "default"); assertThat(ElasticSearchConfiguration.fromProperties(configuration) - .getSslTrustConfiguration()) - .isEqualTo(SSLTrustConfiguration.defaultBehavior()); + .getSslConfiguration()) + .isEqualTo(SSLConfiguration.defaultBehavior()); } } @@ -141,8 +208,11 @@ class ElasticSearchConfigurationTest { configuration.addProperty("elasticsearch.hostScheme.https.sslValidationStrategy", "ignore"); assertThat(ElasticSearchConfiguration.fromProperties(configuration) - .getSslTrustConfiguration()) - .isEqualTo(SSLTrustConfiguration.ignore()); + .getSslConfiguration()) + .isEqualTo(SSLConfiguration.builder() + .strategyIgnore() + .defaultHostNameVerifier() + .build()); } } @@ -206,18 +276,20 @@ class ElasticSearchConfigurationTest { PropertiesConfiguration configuration = new PropertiesConfiguration(); configuration.addProperty("elasticsearch.hosts", "127.0.0.1"); - String strategy = "override"; String trustStorePath = "src/test/resources/auth-es/server.jks"; String trustStorePassword = "secret"; - configuration.addProperty("elasticsearch.hostScheme.https.sslValidationStrategy", strategy); + configuration.addProperty("elasticsearch.hostScheme.https.sslValidationStrategy", "override"); configuration.addProperty("elasticsearch.hostScheme.https.trustStorePath", trustStorePath); configuration.addProperty("elasticsearch.hostScheme.https.trustStorePassword", trustStorePassword); + configuration.addProperty("elasticsearch.hostScheme.https.hostNameVerifier", "default"); assertThat(ElasticSearchConfiguration.fromProperties(configuration) - .getSslTrustConfiguration()) - .isEqualTo(SSLTrustConfiguration.override( - SSLTrustStore.of(trustStorePath, trustStorePassword))); + .getSslConfiguration()) + .isEqualTo(SSLConfiguration.builder() + .strategyOverride(SSLTrustStore.of(trustStorePath, trustStorePassword)) + .defaultHostNameVerifier() + .build()); } } } diff --git a/dockerfiles/run/guice/cassandra-ldap/destination/conf/elasticsearch.properties b/dockerfiles/run/guice/cassandra-ldap/destination/conf/elasticsearch.properties index b2eefc5..74e5a3d 100644 --- a/dockerfiles/run/guice/cassandra-ldap/destination/conf/elasticsearch.properties +++ b/dockerfiles/run/guice/cassandra-ldap/destination/conf/elasticsearch.properties @@ -45,6 +45,12 @@ elasticsearch.port=9200 # You need to specify both trustStorePath and trustStorePassword # elasticsearch.hostScheme.https.trustStorePassword=myJKSPassword +# Optional. default is `default` +# Configure Elasticsearch rest client to use host name verifier during SSL handshake +# default: using the default hostname verifier provided by apache http client. +# accept_any_hostname: accept any hostname (not recommended). +# elasticsearch.hostScheme.https.hostNameVerifier=default + # Optional. # Basic auth username to access elasticsearch. # Ignore elasticsearch.user and elasticsearch.password to not be using authentication (default behaviour). diff --git a/dockerfiles/run/guice/cassandra-rabbitmq-ldap/destination/conf/elasticsearch.properties b/dockerfiles/run/guice/cassandra-rabbitmq-ldap/destination/conf/elasticsearch.properties index eecf449..0ea86db 100644 --- a/dockerfiles/run/guice/cassandra-rabbitmq-ldap/destination/conf/elasticsearch.properties +++ b/dockerfiles/run/guice/cassandra-rabbitmq-ldap/destination/conf/elasticsearch.properties @@ -44,6 +44,12 @@ elasticsearch.port=9200 # You need to specify both trustStorePath and trustStorePassword # elasticsearch.hostScheme.https.trustStorePassword=myJKSPassword +# Optional. default is `default` +# Configure Elasticsearch rest client to use host name verifier during SSL handshake +# default: using the default hostname verifier provided by apache http client. +# accept_any_hostname: accept any hostname (not recommended). +# elasticsearch.hostScheme.https.hostNameVerifier=default + # Optional. # Basic auth username to access elasticsearch. # Ignore elasticsearch.user and elasticsearch.password to not be using authentication (default behaviour). diff --git a/dockerfiles/run/guice/cassandra-rabbitmq/destination/conf/elasticsearch.properties b/dockerfiles/run/guice/cassandra-rabbitmq/destination/conf/elasticsearch.properties index eecf449..16ea216 100644 --- a/dockerfiles/run/guice/cassandra-rabbitmq/destination/conf/elasticsearch.properties +++ b/dockerfiles/run/guice/cassandra-rabbitmq/destination/conf/elasticsearch.properties @@ -44,6 +44,12 @@ elasticsearch.port=9200 # You need to specify both trustStorePath and trustStorePassword # elasticsearch.hostScheme.https.trustStorePassword=myJKSPassword +# Optional. default is `default` +# Configure Elasticsearch rest client to use host name verifier during SSL handshake +# default: using the default hostname verifier provided by apache http client. +# accept_any_hostname: accept any host (not recommended). +# elasticsearch.hostScheme.https.hostNameVerifier=default + # Optional. # Basic auth username to access elasticsearch. # Ignore elasticsearch.user and elasticsearch.password to not be using authentication (default behaviour). diff --git a/dockerfiles/run/guice/cassandra/destination/conf/elasticsearch.properties b/dockerfiles/run/guice/cassandra/destination/conf/elasticsearch.properties index b2eefc5..74e5a3d 100644 --- a/dockerfiles/run/guice/cassandra/destination/conf/elasticsearch.properties +++ b/dockerfiles/run/guice/cassandra/destination/conf/elasticsearch.properties @@ -45,6 +45,12 @@ elasticsearch.port=9200 # You need to specify both trustStorePath and trustStorePassword # elasticsearch.hostScheme.https.trustStorePassword=myJKSPassword +# Optional. default is `default` +# Configure Elasticsearch rest client to use host name verifier during SSL handshake +# default: using the default hostname verifier provided by apache http client. +# accept_any_hostname: accept any hostname (not recommended). +# elasticsearch.hostScheme.https.hostNameVerifier=default + # Optional. # Basic auth username to access elasticsearch. # Ignore elasticsearch.user and elasticsearch.password to not be using authentication (default behaviour). diff --git a/src/site/xdoc/server/config-elasticsearch.xml b/src/site/xdoc/server/config-elasticsearch.xml index f763272..789f044 100644 --- a/src/site/xdoc/server/config-elasticsearch.xml +++ b/src/site/xdoc/server/config-elasticsearch.xml @@ -252,6 +252,21 @@ Once you chose <strong>override</strong>, you need to specify both trustStorePath and trustStorePassword. </dd> </dl> + + <p> + During SSL handshaking, the client can determine whether accept or reject connecting to a remote server by its hostname. + You can configure to use which HostNameVerifier in the client. + </p> + <dl> + <dt><strong>elasticsearch.hostScheme.https.hostNameVerifier</strong></dt> + <dd> + Optional. Default is <strong>default</strong>. + </dd> + <dd> + default: using the default hostname verifier provided by apache http client. + accept_any_hostname: accept any host (not recommended). + </dd> + </dl> </section> </body> --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
