+ * Use this provider if you don't want the client to present any certificates to the remote TLS host.
+ */
+@SdkInternalApi
+public final class NoneTlsKeyManagersProvider implements TlsKeyManagersProvider {
+ private static final NoneTlsKeyManagersProvider INSTANCE = new NoneTlsKeyManagersProvider();
+
+ private NoneTlsKeyManagersProvider() {
+ }
+
+ @Override
+ public KeyManager[] keyManagers() {
+ return null;
+ }
+
+ public static NoneTlsKeyManagersProvider getInstance() {
+ return INSTANCE;
+ }
+}
diff --git a/http-client-spi/src/test/java/software/amazon/awssdk/http/TlsKeyManagersProviderTest.java b/http-client-spi/src/test/java/software/amazon/awssdk/http/TlsKeyManagersProviderTest.java
new file mode 100644
index 000000000000..79412f79c334
--- /dev/null
+++ b/http-client-spi/src/test/java/software/amazon/awssdk/http/TlsKeyManagersProviderTest.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.http;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import org.junit.Test;
+
+public class TlsKeyManagersProviderTest {
+
+ @Test
+ public void noneProvider_returnsProviderThatReturnsNull() {
+ assertThat(TlsKeyManagersProvider.noneProvider().keyManagers()).isNull();
+ }
+}
diff --git a/http-client-spi/src/test/java/software/amazon/awssdk/http/software/amazon/awssdk/internal/http/NoneTlsKeyManagersProviderTest.java b/http-client-spi/src/test/java/software/amazon/awssdk/http/software/amazon/awssdk/internal/http/NoneTlsKeyManagersProviderTest.java
new file mode 100644
index 000000000000..2e3098e62de4
--- /dev/null
+++ b/http-client-spi/src/test/java/software/amazon/awssdk/http/software/amazon/awssdk/internal/http/NoneTlsKeyManagersProviderTest.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.http.software.amazon.awssdk.internal.http;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import org.junit.Test;
+import software.amazon.awssdk.internal.http.NoneTlsKeyManagersProvider;
+
+public class NoneTlsKeyManagersProviderTest {
+ @Test
+ public void getInstance_returnsNonNull() {
+ assertThat(NoneTlsKeyManagersProvider.getInstance()).isNotNull();
+ }
+
+ @Test
+ public void keyManagers_returnsNull() {
+ assertThat(NoneTlsKeyManagersProvider.getInstance().keyManagers()).isNull();
+ }
+
+ @Test
+ public void getInstance_returnsSingletonInstance() {
+ NoneTlsKeyManagersProvider provider1 = NoneTlsKeyManagersProvider.getInstance();
+ NoneTlsKeyManagersProvider provider2 = NoneTlsKeyManagersProvider.getInstance();
+ assertThat(provider1 == provider2).isTrue();
+ }
+}
diff --git a/http-clients/apache-client/src/main/java/software/amazon/awssdk/http/apache/ApacheHttpClient.java b/http-clients/apache-client/src/main/java/software/amazon/awssdk/http/apache/ApacheHttpClient.java
index e4c6c9fe10da..b86a74a78604 100644
--- a/http-clients/apache-client/src/main/java/software/amazon/awssdk/http/apache/ApacheHttpClient.java
+++ b/http-clients/apache-client/src/main/java/software/amazon/awssdk/http/apache/ApacheHttpClient.java
@@ -26,6 +26,7 @@
import static software.amazon.awssdk.http.SdkHttpConfigurationOption.MAX_CONNECTIONS;
import static software.amazon.awssdk.http.SdkHttpConfigurationOption.READ_TIMEOUT;
import static software.amazon.awssdk.http.SdkHttpConfigurationOption.REAP_IDLE_CONNECTIONS;
+import static software.amazon.awssdk.http.SdkHttpConfigurationOption.TLS_KEY_MANAGERS_PROVIDER;
import static software.amazon.awssdk.utils.NumericUtils.saturatedCast;
import java.io.IOException;
@@ -381,6 +382,10 @@ public interface Builder extends SdkHttpClient.Builder
+ * The default used by the client will be {@link SystemPropertyTlsKeyManagersProvider}. Configure an instance of
+ * {@link software.amazon.awssdk.internal.http.NoneTlsKeyManagersProvider} or another implementation of
+ * {@link TlsKeyManagersProvider} to override it.
*/
Builder tlsKeyManagersProvider(TlsKeyManagersProvider tlsKeyManagersProvider);
}
@@ -392,7 +397,6 @@ private static final class DefaultBuilder implements Builder {
private Boolean expectContinueEnabled;
private HttpRoutePlanner httpRoutePlanner;
private CredentialsProvider credentialsProvider;
- private TlsKeyManagersProvider tlsKeyManagersProvider = SystemPropertyTlsKeyManagersProvider.create();
private DefaultBuilder() {
}
@@ -521,7 +525,7 @@ public Builder credentialsProvider(CredentialsProvider credentialsProvider) {
@Override
public Builder tlsKeyManagersProvider(TlsKeyManagersProvider tlsKeyManagersProvider) {
- this.tlsKeyManagersProvider = tlsKeyManagersProvider;
+ standardOptions.put(TLS_KEY_MANAGERS_PROVIDER, tlsKeyManagersProvider);
return this;
}
@@ -565,7 +569,7 @@ public HttpClientConnectionManager create(ApacheHttpClient.DefaultBuilder config
private ConnectionSocketFactory getPreferredSocketFactory(ApacheHttpClient.DefaultBuilder configuration,
AttributeMap standardOptions) {
// TODO v2 custom socket factory
- return new SdkTlsSocketFactory(getSslContext(configuration.tlsKeyManagersProvider, standardOptions),
+ return new SdkTlsSocketFactory(getSslContext(standardOptions),
getHostNameVerifier(standardOptions));
}
@@ -575,7 +579,7 @@ private HostnameVerifier getHostNameVerifier(AttributeMap standardOptions) {
: SSLConnectionSocketFactory.getDefaultHostnameVerifier();
}
- private SSLContext getSslContext(TlsKeyManagersProvider keyManagersProvider, AttributeMap standardOptions) {
+ private SSLContext getSslContext(AttributeMap standardOptions) {
TrustManager[] trustManagers = null;
if (standardOptions.get(SdkHttpConfigurationOption.TRUST_ALL_CERTIFICATES)) {
log.warn(() -> "SSL Certificate verification is disabled. This is not a safe setting and should only be "
@@ -583,10 +587,8 @@ private SSLContext getSslContext(TlsKeyManagersProvider keyManagersProvider, Att
trustManagers = trustAllTrustManager();
}
- KeyManager[] keyManagers = null;
- if (keyManagersProvider != null) {
- keyManagers = keyManagersProvider.keyManagers();
- }
+ TlsKeyManagersProvider provider = standardOptions.get(TLS_KEY_MANAGERS_PROVIDER);
+ KeyManager[] keyManagers = provider.keyManagers();
try {
SSLContext sslcontext = SSLContext.getInstance("TLS");
diff --git a/http-clients/apache-client/src/test/java/software/amazon/awssdk/http/apache/ApacheClientTlsAuthTest.java b/http-clients/apache-client/src/test/java/software/amazon/awssdk/http/apache/ApacheClientTlsAuthTest.java
index cb00b6e96bfb..314049947c96 100644
--- a/http-clients/apache-client/src/test/java/software/amazon/awssdk/http/apache/ApacheClientTlsAuthTest.java
+++ b/http-clients/apache-client/src/test/java/software/amazon/awssdk/http/apache/ApacheClientTlsAuthTest.java
@@ -21,6 +21,8 @@
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
+import static org.hamcrest.Matchers.anyOf;
+import static org.hamcrest.Matchers.instanceOf;
import static software.amazon.awssdk.utils.JavaSystemSetting.SSL_KEY_STORE;
import static software.amazon.awssdk.utils.JavaSystemSetting.SSL_KEY_STORE_PASSWORD;
import static software.amazon.awssdk.utils.JavaSystemSetting.SSL_KEY_STORE_TYPE;
@@ -30,11 +32,14 @@
import java.net.URI;
import javax.net.ssl.SSLException;
import org.apache.http.NoHttpResponseException;
+import org.hamcrest.Matchers;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
import software.amazon.awssdk.http.FileStoreTlsKeyManagersProvider;
import software.amazon.awssdk.http.HttpExecuteRequest;
import software.amazon.awssdk.http.HttpExecuteResponse;
@@ -43,6 +48,7 @@
import software.amazon.awssdk.http.SdkHttpMethod;
import software.amazon.awssdk.http.SdkHttpRequest;
import software.amazon.awssdk.http.TlsKeyManagersProvider;
+import software.amazon.awssdk.internal.http.NoneTlsKeyManagersProvider;
/**
* Tests to ensure that {@link ApacheHttpClient} can properly support TLS
@@ -53,6 +59,9 @@ public class ApacheClientTlsAuthTest extends ClientTlsAuthTestBase {
private static TlsKeyManagersProvider keyManagersProvider;
private SdkHttpClient client;
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
@BeforeClass
public static void setUp() throws IOException {
ClientTlsAuthTestBase.setUp();
@@ -108,14 +117,9 @@ public void canMakeHttpsRequestWhenKeyProviderConfigured() throws IOException {
@Test
public void requestFailsWhenKeyProviderNotConfigured() throws IOException {
- client = ApacheHttpClient.builder().build();
- try {
- makeRequestWithHttpClient(client);
- fail("HTTP request should have failed");
- } catch (NoHttpResponseException | SSLException | SocketException expected) {
- // The client doesn't seem to consistently throw a single error,
- // and can also vary depending on actual JVM used.
- }
+ thrown.expect(anyOf(instanceOf(NoHttpResponseException.class), instanceOf(SSLException.class)));
+ client = ApacheHttpClient.builder().tlsKeyManagersProvider(NoneTlsKeyManagersProvider.getInstance()).build();
+ makeRequestWithHttpClient(client);
}
@Test
@@ -151,6 +155,22 @@ public void defaultTlsKeyManagersProviderIsSystemPropertyProvider() throws IOExc
}
}
+ @Test
+ public void defaultTlsKeyManagersProviderIsSystemPropertyProvider_explicitlySetToNull() throws IOException {
+ System.setProperty(SSL_KEY_STORE.property(), clientKeyStore.toAbsolutePath().toString());
+ System.setProperty(SSL_KEY_STORE_TYPE.property(), CLIENT_STORE_TYPE);
+ System.setProperty(SSL_KEY_STORE_PASSWORD.property(), STORE_PASSWORD);
+
+ client = ApacheHttpClient.builder().tlsKeyManagersProvider(null).build();
+ try {
+ makeRequestWithHttpClient(client);
+ } finally {
+ System.clearProperty(SSL_KEY_STORE.property());
+ System.clearProperty(SSL_KEY_STORE_TYPE.property());
+ System.clearProperty(SSL_KEY_STORE_PASSWORD.property());
+ }
+ }
+
private HttpExecuteResponse makeRequestWithHttpClient(SdkHttpClient httpClient) throws IOException {
SdkHttpRequest httpRequest = SdkHttpFullRequest.builder()
.method(SdkHttpMethod.GET)
diff --git a/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/NettyNioAsyncHttpClient.java b/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/NettyNioAsyncHttpClient.java
index ff76b6720657..751c3d77937e 100644
--- a/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/NettyNioAsyncHttpClient.java
+++ b/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/NettyNioAsyncHttpClient.java
@@ -23,6 +23,7 @@
import static software.amazon.awssdk.http.SdkHttpConfigurationOption.MAX_PENDING_CONNECTION_ACQUIRES;
import static software.amazon.awssdk.http.SdkHttpConfigurationOption.READ_TIMEOUT;
import static software.amazon.awssdk.http.SdkHttpConfigurationOption.REAP_IDLE_CONNECTIONS;
+import static software.amazon.awssdk.http.SdkHttpConfigurationOption.TLS_KEY_MANAGERS_PROVIDER;
import static software.amazon.awssdk.http.SdkHttpConfigurationOption.WRITE_TIMEOUT;
import static software.amazon.awssdk.http.nio.netty.internal.NettyConfiguration.EVENTLOOP_SHUTDOWN_FUTURE_TIMEOUT_SECONDS;
import static software.amazon.awssdk.http.nio.netty.internal.NettyConfiguration.EVENTLOOP_SHUTDOWN_QUIET_PERIOD_SECONDS;
@@ -48,6 +49,8 @@
import software.amazon.awssdk.http.Protocol;
import software.amazon.awssdk.http.SdkHttpConfigurationOption;
import software.amazon.awssdk.http.SdkHttpRequest;
+import software.amazon.awssdk.http.SystemPropertyTlsKeyManagersProvider;
+import software.amazon.awssdk.http.TlsKeyManagersProvider;
import software.amazon.awssdk.http.async.AsyncExecuteRequest;
import software.amazon.awssdk.http.async.SdkAsyncHttpClient;
import software.amazon.awssdk.http.nio.netty.internal.AwaitCloseChannelPoolMap;
@@ -354,6 +357,18 @@ public interface Builder extends SdkAsyncHttpClient.Builder