From 1e3f5c342be3dc813c8b1ff0156ddd2b68df9ede Mon Sep 17 00:00:00 2001 From: Alex Belyaev Date: Mon, 5 Apr 2021 12:06:35 +0200 Subject: [PATCH 1/2] Properly close input streams when loading key stores See gh-25884 --- .../autoconfigure/couchbase/CouchbaseAutoConfiguration.java | 5 ++++- .../boot/web/embedded/netty/SslServerCustomizer.java | 5 ++++- .../boot/web/embedded/undertow/SslBuilderCustomizer.java | 5 ++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfiguration.java index 52439a9974..08c7c58eb8 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfiguration.java @@ -16,6 +16,7 @@ package org.springframework.boot.autoconfigure.couchbase; +import java.io.InputStream; import java.net.URL; import java.security.KeyStore; @@ -107,7 +108,9 @@ public class CouchbaseAutoConfiguration { private KeyStore loadKeyStore(String resource, String keyStorePassword) throws Exception { KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType()); URL url = ResourceUtils.getURL(resource); - store.load(url.openStream(), (keyStorePassword != null) ? keyStorePassword.toCharArray() : null); + try (InputStream inputStream = url.openStream()) { + store.load(inputStream, (keyStorePassword != null) ? keyStorePassword.toCharArray() : null); + } return store; } 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 eeab11a5f9..f9123a70ec 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 @@ -16,6 +16,7 @@ package org.springframework.boot.web.embedded.netty; +import java.io.InputStream; import java.net.Socket; import java.net.URL; import java.security.InvalidAlgorithmParameterException; @@ -170,7 +171,9 @@ public class SslServerCustomizer implements NettyServerCustomizer { KeyStore store = (provider != null) ? KeyStore.getInstance(type, provider) : KeyStore.getInstance(type); try { URL url = ResourceUtils.getURL(resource); - store.load(url.openStream(), (password != null) ? password.toCharArray() : null); + try (InputStream inputStream = url.openStream()) { + store.load(inputStream, (password != null) ? password.toCharArray() : null); + } return store; } catch (Exception ex) { diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/SslBuilderCustomizer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/SslBuilderCustomizer.java index 65c948be88..434448c670 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/SslBuilderCustomizer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/SslBuilderCustomizer.java @@ -16,6 +16,7 @@ package org.springframework.boot.web.embedded.undertow; +import java.io.InputStream; import java.net.InetAddress; import java.net.Socket; import java.net.URL; @@ -181,7 +182,9 @@ class SslBuilderCustomizer implements UndertowBuilderCustomizer { KeyStore store = (provider != null) ? KeyStore.getInstance(type, provider) : KeyStore.getInstance(type); try { URL url = ResourceUtils.getURL(resource); - store.load(url.openStream(), (password != null) ? password.toCharArray() : null); + try (InputStream inputStream = url.openStream()) { + store.load(inputStream, (password != null) ? password.toCharArray() : null); + } return store; } catch (Exception ex) { From 25b7495d8e03eb2b06c11c35a1a83fa58bbbfca7 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 8 Apr 2021 09:21:46 +0200 Subject: [PATCH 2/2] Polish "Properly close input streams when loading key stores" See gh-25884 --- .../couchbase/CouchbaseAutoConfiguration.java | 6 +++--- .../embedded/netty/SslServerCustomizer.java | 6 +++--- .../undertow/SslBuilderCustomizer.java | 6 +++--- .../tomcat/SslConnectorCustomizerTests.java | 6 +++--- ...AbstractReactiveWebServerFactoryTests.java | 6 ++++-- .../SslConfigurationValidatorTests.java | 8 ++++--- .../AbstractServletWebServerFactoryTests.java | 21 ++++++++++++------- 7 files changed, 34 insertions(+), 25 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfiguration.java index 08c7c58eb8..9b6d79a54a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -108,8 +108,8 @@ public class CouchbaseAutoConfiguration { private KeyStore loadKeyStore(String resource, String keyStorePassword) throws Exception { KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType()); URL url = ResourceUtils.getURL(resource); - try (InputStream inputStream = url.openStream()) { - store.load(inputStream, (keyStorePassword != null) ? keyStorePassword.toCharArray() : null); + try (InputStream stream = url.openStream()) { + store.load(stream, (keyStorePassword != null) ? keyStorePassword.toCharArray() : null); } return store; } 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 f9123a70ec..f8ff93d3c7 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -171,8 +171,8 @@ public class SslServerCustomizer implements NettyServerCustomizer { KeyStore store = (provider != null) ? KeyStore.getInstance(type, provider) : KeyStore.getInstance(type); try { URL url = ResourceUtils.getURL(resource); - try (InputStream inputStream = url.openStream()) { - store.load(inputStream, (password != null) ? password.toCharArray() : null); + try (InputStream stream = url.openStream()) { + store.load(stream, (password != null) ? password.toCharArray() : null); } return store; } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/SslBuilderCustomizer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/SslBuilderCustomizer.java index 434448c670..796dd920d9 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/SslBuilderCustomizer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/SslBuilderCustomizer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -182,8 +182,8 @@ class SslBuilderCustomizer implements UndertowBuilderCustomizer { KeyStore store = (provider != null) ? KeyStore.getInstance(type, provider) : KeyStore.getInstance(type); try { URL url = ResourceUtils.getURL(resource); - try (InputStream inputStream = url.openStream()) { - store.load(inputStream, (password != null) ? password.toCharArray() : null); + try (InputStream stream = url.openStream()) { + store.load(stream, (password != null) ? password.toCharArray() : null); } return store; } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/SslConnectorCustomizerTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/SslConnectorCustomizerTests.java index 038604a515..7c0deaa985 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/SslConnectorCustomizerTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/SslConnectorCustomizerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -220,8 +220,8 @@ class SslConnectorCustomizerTests { private KeyStore loadStore() throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException { KeyStore keyStore = KeyStore.getInstance("JKS"); Resource resource = new ClassPathResource("test.jks"); - try (InputStream inputStream = resource.getInputStream()) { - keyStore.load(inputStream, "secret".toCharArray()); + try (InputStream stream = resource.getInputStream()) { + keyStore.load(stream, "secret".toCharArray()); return keyStore; } } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java index 88b7f78595..11f379fa5a 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java @@ -16,8 +16,8 @@ package org.springframework.boot.web.reactive.server; -import java.io.File; import java.io.FileInputStream; +import java.io.InputStream; import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; import java.security.KeyStore; @@ -228,7 +228,9 @@ public abstract class AbstractReactiveWebServerFactoryTests { protected ReactorClientHttpConnector buildTrustAllSslWithClientKeyConnector() throws Exception { KeyStore clientKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - clientKeyStore.load(new FileInputStream(new File("src/test/resources/test.jks")), "secret".toCharArray()); + try (InputStream stream = new FileInputStream("src/test/resources/test.jks")) { + clientKeyStore.load(stream, "secret".toCharArray()); + } KeyManagerFactory clientKeyManagerFactory = KeyManagerFactory .getInstance(KeyManagerFactory.getDefaultAlgorithm()); clientKeyManagerFactory.init(clientKeyStore, "password".toCharArray()); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/server/SslConfigurationValidatorTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/server/SslConfigurationValidatorTests.java index 373b126f09..aef81cb9ca 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/server/SslConfigurationValidatorTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/server/SslConfigurationValidatorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -16,8 +16,8 @@ package org.springframework.boot.web.server; -import java.io.File; import java.io.FileInputStream; +import java.io.InputStream; import java.security.KeyStore; import java.security.KeyStoreException; @@ -43,7 +43,9 @@ class SslConfigurationValidatorTests { @BeforeEach void loadKeystore() throws Exception { this.keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - this.keyStore.load(new FileInputStream(new File("src/test/resources/test.jks")), "secret".toCharArray()); + try (InputStream stream = new FileInputStream("src/test/resources/test.jks")) { + this.keyStore.load(stream, "secret".toCharArray()); + } } @Test diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactoryTests.java index 9c76d168a9..632f32279c 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactoryTests.java @@ -17,7 +17,6 @@ package org.springframework.boot.web.servlet.server; import java.io.File; -import java.io.FileInputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; @@ -126,6 +125,7 @@ import org.springframework.boot.web.servlet.ServletContextInitializer; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.boot.web.servlet.server.Session.SessionTrackingMode; import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; @@ -542,7 +542,7 @@ public abstract class AbstractServletWebServerFactoryTests { this.webServer = factory.getWebServer(); this.webServer.start(); KeyStore keyStore = KeyStore.getInstance("pkcs12"); - keyStore.load(new FileInputStream(new File("src/test/resources/test.p12")), "secret".toCharArray()); + loadStore(keyStore, new FileSystemResource("src/test/resources/test.p12")); SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory( new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy()) .loadKeyMaterial(keyStore, "secret".toCharArray()).build()); @@ -559,7 +559,7 @@ public abstract class AbstractServletWebServerFactoryTests { this.webServer = factory.getWebServer(); this.webServer.start(); KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - keyStore.load(new FileInputStream(new File("src/test/resources/test.jks")), "secret".toCharArray()); + loadStore(keyStore, new FileSystemResource("src/test/resources/test.jks")); SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory( new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy()) .loadKeyMaterial(keyStore, "password".toCharArray()).build()); @@ -592,7 +592,7 @@ public abstract class AbstractServletWebServerFactoryTests { this.webServer = factory.getWebServer(); this.webServer.start(); KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - keyStore.load(new FileInputStream(new File("src/test/resources/test.jks")), "secret".toCharArray()); + loadStore(keyStore, new FileSystemResource("src/test/resources/test.jks")); SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory( new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy()) .loadKeyMaterial(keyStore, "password".toCharArray()).build()); @@ -630,7 +630,7 @@ public abstract class AbstractServletWebServerFactoryTests { this.webServer = factory.getWebServer(); this.webServer.start(); KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - keyStore.load(new FileInputStream(new File("src/test/resources/test.jks")), "secret".toCharArray()); + loadStore(keyStore, new FileSystemResource("src/test/resources/test.jks")); SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory( new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy()) .loadKeyMaterial(keyStore, "password".toCharArray()).build()); @@ -1354,9 +1354,14 @@ public abstract class AbstractServletWebServerFactoryTests { private KeyStore loadStore() throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException { KeyStore keyStore = KeyStore.getInstance("JKS"); Resource resource = new ClassPathResource("test.jks"); - try (InputStream inputStream = resource.getInputStream()) { - keyStore.load(inputStream, "secret".toCharArray()); - return keyStore; + loadStore(keyStore, resource); + return keyStore; + } + + private void loadStore(KeyStore keyStore, Resource resource) + throws IOException, NoSuchAlgorithmException, CertificateException { + try (InputStream stream = resource.getInputStream()) { + keyStore.load(stream, "secret".toCharArray()); } }