Fall back to default SSL provider for unmapped SNI

The RSocket WebSocket transport's HttpServerSslCustomizer kept its own
copy of the SNI provider lookup that returned null for server names
without a mapped SSL bundle. This commit adapts the copy to fall back
to the default provider, as it is done in gh-50301.

See gh-50640

Signed-off-by: Lee JiWon <dlwldnjs1009@gmail.com>
This commit is contained in:
Lee JiWon
2026-05-31 16:31:58 +02:00
committed by Stéphane Nicoll
parent 98048ef12e
commit 9446bd7420
2 changed files with 37 additions and 7 deletions
@@ -269,13 +269,13 @@ public class NettyRSocketServerFactory implements RSocketServerFactory, Configur
}
private static final class HttpServerSslCustomizer extends SslCustomizer {
static final class HttpServerSslCustomizer extends SslCustomizer {
private final SslProvider sslProvider;
private final Map<String, SslProvider> serverNameSslProviders;
private HttpServerSslCustomizer(Ssl.@Nullable ClientAuth clientAuth, SslBundle sslBundle,
HttpServerSslCustomizer(Ssl.@Nullable ClientAuth clientAuth, SslBundle sslBundle,
Map<String, SslBundle> serverNameSslBundles) {
super(Ssl.ClientAuth.map(clientAuth, ClientAuth.NONE, ClientAuth.OPTIONAL, ClientAuth.REQUIRE));
this.sslProvider = createSslProvider(sslBundle);
@@ -287,11 +287,13 @@ public class NettyRSocketServerFactory implements RSocketServerFactory, Configur
}
private void applySecurity(SslContextSpec spec) {
spec.sslContext(this.sslProvider.getSslContext()).setSniAsyncMappings((serverName, promise) -> {
SslProvider provider = (serverName != null) ? this.serverNameSslProviders.get(serverName)
: this.sslProvider;
return promise.setSuccess(provider);
});
spec.sslContext(this.sslProvider.getSslContext())
.setSniAsyncMappings((serverName, promise) -> promise.setSuccess(getSslProvider(serverName)));
}
SslProvider getSslProvider(@Nullable String serverName) {
return (serverName != null) ? this.serverNameSslProviders.getOrDefault(serverName, this.sslProvider)
: this.sslProvider;
}
private Map<String, SslProvider> createServerNameSslProviders(Map<String, SslBundle> serverNameSslBundles) {
@@ -20,6 +20,8 @@ import java.net.InetSocketAddress;
import java.nio.channels.ClosedChannelException;
import java.time.Duration;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.Callable;
import io.netty.buffer.PooledByteBufAllocator;
@@ -267,6 +269,26 @@ class NettyRSocketServerFactoryTests {
testBasicSslWithPemCertificateFromBundle(testCert, testKey, testCert, Transport.WEBSOCKET);
}
@Test
@WithPackageResources({ "test-cert.pem", "test-key.pem" })
void websocketTransportSslProviderFallsBackToDefaultWhenServerNameIsUnmapped() {
SslBundle defaultBundle = createBundle("test-cert.pem", "test-key.pem");
SslBundle mappedBundle = createBundle("test-cert.pem", "test-key.pem");
NettyRSocketServerFactory.HttpServerSslCustomizer customizer = new NettyRSocketServerFactory.HttpServerSslCustomizer(
Ssl.ClientAuth.NONE, defaultBundle, Map.of("mapped.example", mappedBundle));
assertThat(customizer.getSslProvider("unmapped.example")).isSameAs(customizer.getSslProvider(null));
}
@Test
@WithPackageResources({ "test-cert.pem", "test-key.pem" })
@SuppressWarnings("NullAway") // Test null check
void websocketTransportSslProviderReturnsDefaultWhenServerNameIsNull() {
SslBundle defaultBundle = createBundle("test-cert.pem", "test-key.pem");
NettyRSocketServerFactory.HttpServerSslCustomizer customizer = new NettyRSocketServerFactory.HttpServerSslCustomizer(
Ssl.ClientAuth.NONE, defaultBundle, Collections.emptyMap());
assertThat(customizer.getSslProvider(null)).isNotNull();
}
private void checkEchoRequest() {
String payload = "test payload";
assertThat(this.requester).isNotNull();
@@ -338,6 +360,12 @@ class NettyRSocketServerFactoryTests {
checkEchoRequest();
}
private static SslBundle createBundle(String certificate, String certificatePrivateKey) {
PemSslStoreDetails keyStoreDetails = PemSslStoreDetails.forCertificate("classpath:" + certificate)
.withPrivateKey("classpath:" + certificatePrivateKey);
return SslBundle.of(new PemSslStoreBundle(keyStoreDetails, null));
}
@Test
void tcpTransportSslRejectsInsecureClient() {
NettyRSocketServerFactory factory = getFactory();