Skip to content

Replace deprecated SSLConnectionSocketFactory with recommended API #6281

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
import org.apache.hc.client5.http.ssl.DefaultHostnameVerifier;
import org.apache.hc.client5.http.ssl.NoopHostnameVerifier;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
import org.apache.hc.client5.http.ssl.TlsSocketStrategy;
import org.apache.hc.core5.http.ClassicHttpResponse;
import org.apache.hc.core5.http.Header;
import org.apache.hc.core5.http.HttpEntity;
Expand Down Expand Up @@ -90,6 +91,7 @@
import software.amazon.awssdk.http.apache5.internal.conn.IdleConnectionReaper;
import software.amazon.awssdk.http.apache5.internal.conn.SdkConnectionKeepAliveStrategy;
import software.amazon.awssdk.http.apache5.internal.conn.SdkTlsSocketFactory;
import software.amazon.awssdk.http.apache5.internal.conn.SslSocketFactoryToTlsStrategyAdapter;
import software.amazon.awssdk.http.apache5.internal.impl.Apache5HttpRequestFactory;
import software.amazon.awssdk.http.apache5.internal.impl.Apache5SdkHttpClient;
import software.amazon.awssdk.http.apache5.internal.impl.ConnectionManagerAwareHttpClient;
Expand Down Expand Up @@ -452,13 +454,28 @@ public interface Builder extends SdkHttpClient.Builder<Apache5HttpClient.Builder
Builder dnsResolver(DnsResolver dnsResolver);

/**
* @deprecated this has been replaced with {{@link #tlsSocketStrategy(TlsSocketStrategy)}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we explain that this is here to ease migration from 4.5.x?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

* Configuration that defines a custom Socket factory. If set to a null value, a default factory is used.
* <p>
* When set to a non-null value, the use of a custom factory implies the configuration options TRUST_ALL_CERTIFICATES,
* TLS_TRUST_MANAGERS_PROVIDER, and TLS_KEY_MANAGERS_PROVIDER are ignored.
*/
@Deprecated
Builder socketFactory(SSLConnectionSocketFactory socketFactory);


/**
* Configure a custom TLS strategy for SSL/TLS connections.
* This is the preferred method over the deprecated {@link #socketFactory(SSLConnectionSocketFactory)}.
*
* @param tlsSocketStrategy The TLS strategy to use for upgrading connections to TLS.
* If null, default TLS configuration will be used.
* @return This builder for method chaining

*/

Builder tlsSocketStrategy(TlsSocketStrategy tlsSocketStrategy);

/**
* Configuration that defines an HTTP route planner that computes the route an HTTP request should take.
* May not be used in conjunction with {@link #proxyConfiguration(ProxyConfiguration)}.
Expand Down Expand Up @@ -515,7 +532,8 @@ private static final class DefaultBuilder implements Builder {
private HttpRoutePlanner httpRoutePlanner;
private CredentialsProvider credentialsProvider;
private DnsResolver dnsResolver;
private SSLConnectionSocketFactory socketFactory;
private SSLConnectionSocketFactory legacySocketFactory;
private TlsSocketStrategy tlsStrategy;

private DefaultBuilder() {
}
Expand Down Expand Up @@ -638,14 +656,22 @@ public void setDnsResolver(DnsResolver dnsResolver) {

@Override
public Builder socketFactory(SSLConnectionSocketFactory socketFactory) {
this.socketFactory = socketFactory;
this.legacySocketFactory = socketFactory;
this.tlsStrategy = null; // Clear any previously set strategy
return this;
}

public void setSocketFactory(SSLConnectionSocketFactory socketFactory) {
socketFactory(socketFactory);
}

@Override
public Builder tlsSocketStrategy(TlsSocketStrategy tlsSocketStrategy) {
this.tlsStrategy = tlsSocketStrategy;
this.legacySocketFactory = null; // Clear any legacy factory
return this;
}

@Override
public Builder httpRoutePlanner(HttpRoutePlanner httpRoutePlanner) {
this.httpRoutePlanner = httpRoutePlanner;
Expand Down Expand Up @@ -714,20 +740,33 @@ public SdkHttpClient buildWithDefaults(AttributeMap serviceDefaults) {
SdkHttpConfigurationOption.GLOBAL_HTTP_DEFAULTS);
return new Apache5HttpClient(this, resolvedOptions);
}

// Internal method to get the effective TLS strategy
TlsSocketStrategy getEffectiveTlsStrategy() {
if (tlsStrategy != null) {
return tlsStrategy;
}
if (legacySocketFactory != null) {
return new SslSocketFactoryToTlsStrategyAdapter(legacySocketFactory);
}
return null;
}
}

private static class ApacheConnectionManagerFactory {

public PoolingHttpClientConnectionManager create(Apache5HttpClient.DefaultBuilder configuration,
AttributeMap standardOptions) {
// TODO : Deprecated method needs to be removed with new replacements
SSLConnectionSocketFactory sslsf = getPreferredSocketFactory(configuration, standardOptions);
AttributeMap standardOptions) {

TlsSocketStrategy tlsStrategy = getPreferredTlsStrategy(configuration, standardOptions);

PoolingHttpClientConnectionManagerBuilder builder =
PoolingHttpClientConnectionManagerBuilder.create()
.setSSLSocketFactory(sslsf)
.setTlsSocketStrategy(tlsStrategy)
.setSchemePortResolver(DefaultSchemePortResolver.INSTANCE)
.setDnsResolver(configuration.dnsResolver);


Duration connectionTtl = standardOptions.get(SdkHttpConfigurationOption.CONNECTION_TIME_TO_LIVE);
if (!connectionTtl.isZero()) {
// Skip TTL=0 to maintain backward compatibility (infinite in 4.x vs immediate expiration in 5.x)
Expand All @@ -739,11 +778,15 @@ public PoolingHttpClientConnectionManager create(Apache5HttpClient.DefaultBuilde
return builder.build();
}

private SSLConnectionSocketFactory getPreferredSocketFactory(Apache5HttpClient.DefaultBuilder configuration,
AttributeMap standardOptions) {
return Optional.ofNullable(configuration.socketFactory)
.orElseGet(() -> new SdkTlsSocketFactory(getSslContext(standardOptions),
getHostNameVerifier(standardOptions)));
private TlsSocketStrategy getPreferredTlsStrategy(Apache5HttpClient.DefaultBuilder configuration,
AttributeMap standardOptions) {
// Use the effective strategy which handles both legacy and new approaches
TlsSocketStrategy configuredStrategy = configuration.getEffectiveTlsStrategy();
if (configuredStrategy != null) {
return configuredStrategy;
}
return new SdkTlsSocketFactory(getSslContext(standardOptions),
getHostNameVerifier(standardOptions));
}


Expand Down Expand Up @@ -815,6 +858,7 @@ private SocketConfig buildSocketConfig(AttributeMap standardOptions) {
.build();
}


}

private static class LocalAddressRoutePlanner extends DefaultRoutePlanner {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public static HttpClientConnectionManager wrap(HttpClientConnectionManager orig)
/**
* Further wraps {@link LeaseRequest} to capture performance metrics.
*/
private static class InstrumentedHttpClientConnectionManager extends DelegatingHttpClientConnectionManager {
private static final class InstrumentedHttpClientConnectionManager extends DelegatingHttpClientConnectionManager {

private InstrumentedHttpClientConnectionManager(HttpClientConnectionManager delegate) {
super(delegate);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ static LeaseRequest wrap(LeaseRequest orig) {
/**
* Measures the latency of {@link LeaseRequest#get(Timeout)}.
*/
private static class InstrumentedConnectionRequest extends DelegatingConnectionRequest {
private static final class InstrumentedConnectionRequest extends DelegatingConnectionRequest {

private InstrumentedConnectionRequest(LeaseRequest delegate) {
super(delegate);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,50 +16,50 @@
package software.amazon.awssdk.http.apache5.internal.conn;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.Arrays;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;
import org.apache.hc.core5.http.protocol.HttpContext;
import org.apache.hc.core5.util.TimeValue;
import software.amazon.awssdk.annotations.SdkInternalApi;
import software.amazon.awssdk.http.apache5.internal.net.SdkSocket;
import software.amazon.awssdk.http.apache5.internal.net.SdkSslSocket;
import software.amazon.awssdk.utils.Logger;

@SdkInternalApi
public class SdkTlsSocketFactory extends SSLConnectionSocketFactory {
public class SdkTlsSocketFactory extends DefaultClientTlsStrategy {

private static final Logger log = Logger.loggerFor(SdkTlsSocketFactory.class);

public SdkTlsSocketFactory(SSLContext sslContext, HostnameVerifier hostnameVerifier) {
super(sslContext, hostnameVerifier);
if (sslContext == null) {
throw new IllegalArgumentException(
"sslContext must not be null. " + "Use SSLContext.getDefault() if you are unsure.");
"sslContext must not be null. Use SSLContext.getDefault() if you are unsure.");
}
}

@Override
protected final void prepareSocket(SSLSocket socket) {
protected void initializeSocket(SSLSocket socket) {
super.initializeSocket(socket);
log.debug(() -> String.format("socket.getSupportedProtocols(): %s, socket.getEnabledProtocols(): %s",
Arrays.toString(socket.getSupportedProtocols()),
Arrays.toString(socket.getEnabledProtocols())));
}

@Override
public Socket connectSocket(TimeValue connectTimeout,
Socket socket,
HttpHost host,
InetSocketAddress remoteAddress,
InetSocketAddress localAddress,
HttpContext context) throws IOException {
log.trace(() -> String.format("Connecting to %s:%s", remoteAddress.getAddress(), remoteAddress.getPort()));
public SSLSocket upgrade(Socket socket,
String target,
int port,
Object attachment,
HttpContext context) throws IOException {
log.trace(() -> String.format("Upgrading socket to TLS for %s:%s", target, port));

Socket connectSocket = super.connectSocket(connectTimeout, socket, host, remoteAddress, localAddress, context);
return new SdkSocket(connectSocket);
SSLSocket upgradedSocket = super.upgrade(socket, target, port, attachment, context);

// Wrap the upgraded SSLSocket in SdkSSLSocket for logging
return new SdkSslSocket(upgradedSocket);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright 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.apache5.internal.conn;

import java.io.IOException;
import java.net.Socket;
import javax.net.ssl.SSLSocket;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
import org.apache.hc.client5.http.ssl.TlsSocketStrategy;
import org.apache.hc.core5.http.protocol.HttpContext;
import software.amazon.awssdk.annotations.SdkInternalApi;

/**
* Adapter to wrap legacy SSLConnectionSocketFactory as TlsSocketStrategy
*/
@SdkInternalApi
public class SslSocketFactoryToTlsStrategyAdapter implements TlsSocketStrategy {

private final SSLConnectionSocketFactory legacySocketFactory;

public SslSocketFactoryToTlsStrategyAdapter(SSLConnectionSocketFactory legacySocketFactory) {
this.legacySocketFactory = legacySocketFactory;
}

@Override
public SSLSocket upgrade(Socket socket,
String target,
int port,
Object attachment,
HttpContext context) throws IOException {
Socket layeredSocket = legacySocketFactory.createLayeredSocket(socket, target, port, context);
if (layeredSocket == null) {
throw new IOException("SSLConnectionSocketFactory.createLayeredSocket returned null");
}
if (!(layeredSocket instanceof SSLSocket)) {
throw new IOException("SSLConnectionSocketFactory.createLayeredSocket did not return an SSLSocket. " +
"Returned type: " + layeredSocket.getClass().getName());
}

return (SSLSocket) layeredSocket;
}
}
Loading
Loading