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 @@ -53,9 +53,10 @@
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
import org.apache.hc.client5.http.protocol.HttpClientContext;
import org.apache.hc.client5.http.routing.HttpRoutePlanner;
import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
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 @@ -87,6 +88,7 @@
import software.amazon.awssdk.http.apache5.internal.DefaultConfiguration;
import software.amazon.awssdk.http.apache5.internal.SdkProxyRoutePlanner;
import software.amazon.awssdk.http.apache5.internal.conn.ClientConnectionManagerFactory;
import software.amazon.awssdk.http.apache5.internal.conn.ConnectionSocketFactoryToTlsStrategyAdapter;
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;
Expand Down Expand Up @@ -452,12 +454,27 @@ 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.
*/
Builder socketFactory(SSLConnectionSocketFactory socketFactory);
@Deprecated
Builder socketFactory(ConnectionSocketFactory socketFactory);


/**
* Configure a custom TLS strategy for SSL/TLS connections.
* This is the preferred method over the deprecated {@link #socketFactory(ConnectionSocketFactory)}.
*
* @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.
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 ConnectionSocketFactory legacySocketFactory;
private TlsSocketStrategy tlsStrategy;

private DefaultBuilder() {
}
Expand Down Expand Up @@ -637,15 +655,23 @@ public void setDnsResolver(DnsResolver dnsResolver) {
}

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

public void setSocketFactory(SSLConnectionSocketFactory socketFactory) {
public void setSocketFactory(ConnectionSocketFactory 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 ConnectionSocketFactoryToTlsStrategyAdapter(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
@@ -0,0 +1,70 @@
/*
* 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.socket.ConnectionSocketFactory;
import org.apache.hc.client5.http.socket.LayeredConnectionSocketFactory;
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 ConnectionSocketFactory as TlsSocketStrategy.
* Supports both plain and layered (SSL/TLS) socket factories.
*/
@SdkInternalApi
public class ConnectionSocketFactoryToTlsStrategyAdapter implements TlsSocketStrategy {

private final ConnectionSocketFactory socketFactory;

public ConnectionSocketFactoryToTlsStrategyAdapter(ConnectionSocketFactory socketFactory) {
this.socketFactory = socketFactory;
}

@Override
public SSLSocket upgrade(Socket socket,
String target,
int port,
Object attachment,
HttpContext context) throws IOException {

// Only LayeredConnectionSocketFactory can upgrade to SSL
if (socketFactory instanceof LayeredConnectionSocketFactory) {
LayeredConnectionSocketFactory layeredFactory = (LayeredConnectionSocketFactory) socketFactory;
Socket upgradedSocket = layeredFactory.createLayeredSocket(socket, target, port, context);

if (upgradedSocket == null) {
throw new IOException("LayeredConnectionSocketFactory.createLayeredSocket returned null");
}
if (!(upgradedSocket instanceof SSLSocket)) {
throw new IOException("LayeredConnectionSocketFactory.createLayeredSocket did not return an SSLSocket. " +
"Returned type: " + upgradedSocket.getClass().getName());
}

return (SSLSocket) upgradedSocket;
}

// For plain socket factories (like PlainConnectionSocketFactory),
// we can't upgrade to TLS, but we shouldn't throw an exception
// Return null to indicate no TLS upgrade is possible/needed
return null;
}


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

}
Loading