diff --git a/client/rest/src/main/java/org/elasticsearch/client/RestClientBuilder.java b/client/rest/src/main/java/org/elasticsearch/client/RestClientBuilder.java index 4466a61d9df..38c9cdbe6e6 100644 --- a/client/rest/src/main/java/org/elasticsearch/client/RestClientBuilder.java +++ b/client/rest/src/main/java/org/elasticsearch/client/RestClientBuilder.java @@ -202,11 +202,18 @@ public final class RestClientBuilder { HttpAsyncClientBuilder httpClientBuilder = HttpAsyncClientBuilder.create().setDefaultRequestConfig(requestConfigBuilder.build()) //default settings for connection pooling may be too constraining - .setMaxConnPerRoute(DEFAULT_MAX_CONN_PER_ROUTE).setMaxConnTotal(DEFAULT_MAX_CONN_TOTAL); + .setMaxConnPerRoute(DEFAULT_MAX_CONN_PER_ROUTE).setMaxConnTotal(DEFAULT_MAX_CONN_TOTAL).useSystemProperties(); if (httpClientConfigCallback != null) { httpClientBuilder = httpClientConfigCallback.customizeHttpClient(httpClientBuilder); } - return httpClientBuilder.build(); + + final HttpAsyncClientBuilder finalBuilder = httpClientBuilder; + return AccessController.doPrivileged(new PrivilegedAction() { + @Override + public CloseableHttpAsyncClient run() { + return finalBuilder.build(); + } + }); } /** diff --git a/client/rest/src/test/java/org/elasticsearch/client/RestClientBuilderIntegTests.java b/client/rest/src/test/java/org/elasticsearch/client/RestClientBuilderIntegTests.java new file mode 100644 index 00000000000..8142fea6d25 --- /dev/null +++ b/client/rest/src/test/java/org/elasticsearch/client/RestClientBuilderIntegTests.java @@ -0,0 +1,119 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.client; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpsConfigurator; +import com.sun.net.httpserver.HttpsServer; +import org.apache.http.HttpHost; +import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement; +import org.elasticsearch.mocksocket.MockHttpServer; +import org.junit.AfterClass; +import org.junit.BeforeClass; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; +import java.io.IOException; +import java.io.InputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.security.KeyStore; + +import static org.hamcrest.Matchers.containsString; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + +/** + * Integration test to validate the builder builds a client with the correct configuration + */ +//animal-sniffer doesn't like our usage of com.sun.net.httpserver.* classes +@IgnoreJRERequirement +public class RestClientBuilderIntegTests extends RestClientTestCase { + + private static HttpsServer httpsServer; + + @BeforeClass + public static void startHttpServer() throws Exception { + httpsServer = MockHttpServer.createHttps(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), 0); + httpsServer.setHttpsConfigurator(new HttpsConfigurator(getSslContext())); + httpsServer.createContext("/", new ResponseHandler()); + httpsServer.start(); + } + + //animal-sniffer doesn't like our usage of com.sun.net.httpserver.* classes + @IgnoreJRERequirement + private static class ResponseHandler implements HttpHandler { + @Override + public void handle(HttpExchange httpExchange) throws IOException { + httpExchange.sendResponseHeaders(200, -1); + httpExchange.close(); + } + } + + @AfterClass + public static void stopHttpServers() throws IOException { + httpsServer.stop(0); + httpsServer = null; + } + + public void testBuilderUsesDefaultSSLContext() throws Exception { + final SSLContext defaultSSLContext = SSLContext.getDefault(); + try { + try (RestClient client = buildRestClient()) { + try { + client.performRequest("GET", "/"); + fail("connection should have been rejected due to SSL handshake"); + } catch (Exception e) { + assertThat(e.getMessage(), containsString("General SSLEngine problem")); + } + } + + SSLContext.setDefault(getSslContext()); + try (RestClient client = buildRestClient()) { + Response response = client.performRequest("GET", "/"); + assertEquals(200, response.getStatusLine().getStatusCode()); + } + } finally { + SSLContext.setDefault(defaultSSLContext); + } + } + + private RestClient buildRestClient() { + InetSocketAddress address = httpsServer.getAddress(); + return RestClient.builder(new HttpHost(address.getHostString(), address.getPort(), "https")).build(); + } + + private static SSLContext getSslContext() throws Exception { + SSLContext sslContext = SSLContext.getInstance("TLS"); + try (InputStream in = RestClientBuilderIntegTests.class.getResourceAsStream("/testks.jks")) { + KeyStore keyStore = KeyStore.getInstance("JKS"); + keyStore.load(in, "password".toCharArray()); + KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); + kmf.init(keyStore, "password".toCharArray()); + TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); + tmf.init(keyStore); + sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + } + return sslContext; + } +} diff --git a/client/rest/src/test/resources/testks.jks b/client/rest/src/test/resources/testks.jks new file mode 100644 index 00000000000..cd706db5e38 Binary files /dev/null and b/client/rest/src/test/resources/testks.jks differ diff --git a/core/src/main/resources/org/elasticsearch/bootstrap/test-framework.policy b/core/src/main/resources/org/elasticsearch/bootstrap/test-framework.policy index e73c5c25723..69881df232f 100644 --- a/core/src/main/resources/org/elasticsearch/bootstrap/test-framework.policy +++ b/core/src/main/resources/org/elasticsearch/bootstrap/test-framework.policy @@ -67,6 +67,8 @@ grant codeBase "${codebase.mocksocket-1.2.jar}" { grant codeBase "${codebase.elasticsearch-rest-client-6.0.0-beta1-SNAPSHOT.jar}" { // rest makes socket connections for rest tests permission java.net.SocketPermission "*", "connect"; + // rest client uses system properties which gets the default proxy + permission java.net.NetPermission "getProxySelector"; }; grant codeBase "${codebase.httpcore-nio-4.4.5.jar}" { @@ -77,4 +79,6 @@ grant codeBase "${codebase.httpcore-nio-4.4.5.jar}" { grant codeBase "${codebase.httpasyncclient-4.1.2.jar}" { // httpasyncclient makes socket connections for rest tests permission java.net.SocketPermission "*", "connect"; + // rest client uses system properties which gets the default proxy + permission java.net.NetPermission "getProxySelector"; }; diff --git a/docs/java-rest/low-level/configuration.asciidoc b/docs/java-rest/low-level/configuration.asciidoc index b0b516305b3..54f7cd28173 100644 --- a/docs/java-rest/low-level/configuration.asciidoc +++ b/docs/java-rest/low-level/configuration.asciidoc @@ -79,6 +79,9 @@ https://hc.apache.org/httpcomponents-asyncclient-dev/httpasyncclient/apidocs/org include-tagged::{doc-tests}/RestClientDocumentation.java[rest-client-config-encrypted-communication] -------------------------------------------------- +If no explicit configuration is provided, the http://docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/JSSERefGuide.html#CustomizingStores[system default configuration] +will be used. + === Others For any other required configuration needed, the Apache HttpAsyncClient docs diff --git a/modules/reindex/src/main/plugin-metadata/plugin-security.policy b/modules/reindex/src/main/plugin-metadata/plugin-security.policy index f9ce0f894d3..e56769c10b4 100644 --- a/modules/reindex/src/main/plugin-metadata/plugin-security.policy +++ b/modules/reindex/src/main/plugin-metadata/plugin-security.policy @@ -21,3 +21,13 @@ grant { // reindex opens socket connections using the rest client permission java.net.SocketPermission "*", "connect"; }; + +grant codeBase "${codebase.elasticsearch-rest-client-6.0.0-beta1-SNAPSHOT.jar}" { + // rest client uses system properties which gets the default proxy + permission java.net.NetPermission "getProxySelector"; +}; + +grant codeBase "${codebase.httpasyncclient-4.1.2.jar}" { + // rest client uses system properties which gets the default proxy + permission java.net.NetPermission "getProxySelector"; +};