From 08194cfee7dd1167e5ba8ab85e7bdaffac45d4ca Mon Sep 17 00:00:00 2001 From: Daeho Kwon Date: Thu, 7 May 2026 02:47:32 +0900 Subject: [PATCH 1/2] Fall back to default SSL provider for unmapped SNI hostnames See gh-50301 Signed-off-by: Daeho Kwon --- .../embedded/netty/SslServerCustomizer.java | 14 ++-- .../netty/SslServerCustomizerTests.java | 75 +++++++++++++++++++ 2 files changed, 84 insertions(+), 5 deletions(-) create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/netty/SslServerCustomizerTests.java diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/SslServerCustomizer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/SslServerCustomizer.java index ea80e03cb18..c9cc3276321 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/SslServerCustomizer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/SslServerCustomizer.java @@ -75,11 +75,15 @@ public class SslServerCustomizer implements NettyServerCustomizer { } 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(String serverName) { + if (serverName == null) { + return this.sslProvider; + } + return this.serverNameSslProviders.getOrDefault(serverName, this.sslProvider); } void updateSslBundle(String serverName, SslBundle sslBundle) { diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/netty/SslServerCustomizerTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/netty/SslServerCustomizerTests.java new file mode 100644 index 00000000000..3f15dca11c7 --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/netty/SslServerCustomizerTests.java @@ -0,0 +1,75 @@ +/* + * Copyright 2012-present the original author or authors. + * + * Licensed 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 + * + * https://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.springframework.boot.web.embedded.netty; + +import java.util.Collections; +import java.util.Map; + +import org.junit.jupiter.api.Test; +import reactor.netty.tcp.SslProvider; + +import org.springframework.boot.ssl.SslBundle; +import org.springframework.boot.ssl.pem.PemSslStoreBundle; +import org.springframework.boot.ssl.pem.PemSslStoreDetails; +import org.springframework.boot.testsupport.classpath.resources.WithPackageResources; +import org.springframework.boot.web.server.Ssl; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link SslServerCustomizer}. + * + * @author Daeho Kwon + */ +class SslServerCustomizerTests { + + @Test + @WithPackageResources({ "1.key", "1.crt", "2.key", "2.crt" }) + void getSslProviderReturnsMappedProviderForKnownServerName() { + SslBundle defaultBundle = createBundle("1.key", "1.crt"); + SslBundle mappedBundle = createBundle("2.key", "2.crt"); + SslServerCustomizer customizer = new SslServerCustomizer(null, Ssl.ClientAuth.NONE, defaultBundle, + Map.of("mapped.example", mappedBundle)); + SslProvider mapped = customizer.getSslProvider("mapped.example"); + assertThat(mapped).isNotNull().isNotSameAs(customizer.getSslProvider(null)); + } + + @Test + @WithPackageResources({ "1.key", "1.crt", "2.key", "2.crt" }) + void getSslProviderFallsBackToDefaultWhenServerNameIsUnmapped() { + SslBundle defaultBundle = createBundle("1.key", "1.crt"); + SslBundle mappedBundle = createBundle("2.key", "2.crt"); + SslServerCustomizer customizer = new SslServerCustomizer(null, Ssl.ClientAuth.NONE, defaultBundle, + Map.of("mapped.example", mappedBundle)); + assertThat(customizer.getSslProvider("unmapped.example")).isSameAs(customizer.getSslProvider(null)); + } + + @Test + @WithPackageResources({ "1.key", "1.crt" }) + void getSslProviderReturnsDefaultWhenServerNameIsNull() { + SslBundle defaultBundle = createBundle("1.key", "1.crt"); + SslServerCustomizer customizer = new SslServerCustomizer(null, Ssl.ClientAuth.NONE, defaultBundle, + Collections.emptyMap()); + assertThat(customizer.getSslProvider(null)).isNotNull(); + } + + private static SslBundle createBundle(String key, String certificate) { + return SslBundle.of(new PemSslStoreBundle( + new PemSslStoreDetails(null, "classpath:" + certificate, "classpath:" + key), null)); + } + +} From 8221bdb9d4cedd3a5cef5d7ba2d476ccc1aa69c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Fri, 29 May 2026 10:54:06 +0200 Subject: [PATCH 2/2] Polish "Fall back to default SSL provider for unmapped SNI hostnames" See gh-50301 --- .../boot/web/embedded/netty/SslServerCustomizer.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/SslServerCustomizer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/SslServerCustomizer.java index c9cc3276321..e8a62685fbe 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/SslServerCustomizer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/SslServerCustomizer.java @@ -80,10 +80,8 @@ public class SslServerCustomizer implements NettyServerCustomizer { } SslProvider getSslProvider(String serverName) { - if (serverName == null) { - return this.sslProvider; - } - return this.serverNameSslProviders.getOrDefault(serverName, this.sslProvider); + return (serverName != null) ? this.serverNameSslProviders.getOrDefault(serverName, this.sslProvider) + : this.sslProvider; } void updateSslBundle(String serverName, SslBundle sslBundle) {