Spring Boot v3.2.0 Ssl Bundle is unable to find the JKS file present inside a library jar. The JKS file is commonly shared across multiple applications and benefits being in a single place (here dependent jar)

ResourceUtils.getURL fails to load the JKS file from classpath like classpath:/common/path/in/jar/app.jks

Same works fine if the JKS file is from within the application

Comment From: scottfrederick

Thanks for getting in touch. I can't reproduce this problem with a trivial sample app and library. It's not clear from your description if the configuration that sets the SSL bundle is in the library or in the application, but it works either way for me.

Since there are so many possible ways to configure an application, we'll need more information to know what's going on. Please provide a complete minimal sample that reproduces the problem. You can share it with us by pushing it to a separate repository on GitHub or by zipping it and attaching it to this issue.

Comment From: syedyusufh

Thanks for the quick revert @scottfrederick

Please find below the 2 projects to reproduce the issue reported. Usage of common-lib for JKS has been the pattern working for us prior to Ssl Bundle by manually configuring the Ssl across WebClient, JMS, Kafka, etc

https://github.com/syedyusufh/common-lib.git https://github.com/syedyusufh/ssl-bundle-error.git

You would be getting the below error,

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.ssl.DefaultSslBundleRegistry]: Factory method 'sslBundleRegistry' threw exception with message: Unable to register SSL bundle 'common'
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:178) ~[spring-beans-6.1.1.jar:6.1.1]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) ~[spring-beans-6.1.1.jar:6.1.1]
    ... 57 common frames omitted
Caused by: java.lang.IllegalStateException: Unable to register SSL bundle 'common'
    at org.springframework.boot.autoconfigure.ssl.SslPropertiesBundleRegistrar.lambda$registerBundles$2(SslPropertiesBundleRegistrar.java:68) ~[spring-boot-autoconfigure-3.2.0.jar:3.2.0]
    at java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:721) ~[na:na]
    at org.springframework.boot.autoconfigure.ssl.SslPropertiesBundleRegistrar.registerBundles(SslPropertiesBundleRegistrar.java:58) ~[spring-boot-autoconfigure-3.2.0.jar:3.2.0]
    at org.springframework.boot.autoconfigure.ssl.SslPropertiesBundleRegistrar.registerBundles(SslPropertiesBundleRegistrar.java:53) ~[spring-boot-autoconfigure-3.2.0.jar:3.2.0]
    at org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration.lambda$sslBundleRegistry$0(SslAutoConfiguration.java:59) ~[spring-boot-autoconfigure-3.2.0.jar:3.2.0]
    at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) ~[na:na]
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) ~[na:na]
    at java.base/java.util.stream.SortedOps$RefSortingSink.end(SortedOps.java:395) ~[na:na]
    at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258) ~[na:na]
    at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258) ~[na:na]
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:510) ~[na:na]
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) ~[na:na]
    at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) ~[na:na]
    at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) ~[na:na]
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:na]
    at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) ~[na:na]
    at org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration.sslBundleRegistry(SslAutoConfiguration.java:59) ~[spring-boot-autoconfigure-3.2.0.jar:3.2.0]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) ~[spring-beans-6.1.1.jar:6.1.1]
    ... 58 common frames omitted
Caused by: java.lang.IllegalStateException: Unable to create key store: Could not load store from 'classpath:/com/sample/common.jks'
    at org.springframework.boot.ssl.jks.JksSslStoreBundle.createKeyStore(JksSslStoreBundle.java:93) ~[spring-boot-3.2.0.jar:3.2.0]
    at org.springframework.boot.ssl.jks.JksSslStoreBundle.<init>(JksSslStoreBundle.java:56) ~[spring-boot-3.2.0.jar:3.2.0]
    at org.springframework.boot.autoconfigure.ssl.PropertiesSslBundle.asSslStoreBundle(PropertiesSslBundle.java:146) ~[spring-boot-autoconfigure-3.2.0.jar:3.2.0]
    at org.springframework.boot.autoconfigure.ssl.PropertiesSslBundle.get(PropertiesSslBundle.java:139) ~[spring-boot-autoconfigure-3.2.0.jar:3.2.0]
    at org.springframework.boot.autoconfigure.ssl.SslPropertiesBundleRegistrar.lambda$registerBundles$0(SslPropertiesBundleRegistrar.java:59) ~[spring-boot-autoconfigure-3.2.0.jar:3.2.0]
    at org.springframework.boot.autoconfigure.ssl.SslPropertiesBundleRegistrar.lambda$registerBundles$2(SslPropertiesBundleRegistrar.java:61) ~[spring-boot-autoconfigure-3.2.0.jar:3.2.0]
    ... 79 common frames omitted
Caused by: java.lang.IllegalStateException: Could not load store from 'classpath:/com/sample/common.jks'
    at org.springframework.boot.ssl.jks.JksSslStoreBundle.loadKeyStore(JksSslStoreBundle.java:122) ~[spring-boot-3.2.0.jar:3.2.0]
    at org.springframework.boot.ssl.jks.JksSslStoreBundle.createKeyStore(JksSslStoreBundle.java:88) ~[spring-boot-3.2.0.jar:3.2.0]
    ... 84 common frames omitted
Caused by: java.io.FileNotFoundException: class path resource [/com/sample/common.jks] cannot be resolved to URL because it does not exist
    at org.springframework.util.ResourceUtils.getURL(ResourceUtils.java:138) ~[spring-core-6.1.1.jar:6.1.1]
    at org.springframework.boot.ssl.jks.JksSslStoreBundle.loadKeyStore(JksSslStoreBundle.java:116) ~[spring-boot-3.2.0.jar:3.2.0]
    ... 85 common frames omitted

Comment From: philwebb

I think that the problem you're seeing is caused by an error in the classpath resource reference. The following values:

spring.ssl.bundle.jks.common.keystore.location: classpath:/com/sample/common.jks
spring.ssl.bundle.jks.common.truststore.location: classpath:/com/sample/common.jks

Should be:

spring.ssl.bundle.jks.common.keystore.location: classpath:com/sample/common.jks
spring.ssl.bundle.jks.common.truststore.location: classpath:com/sample/common.jks

We may have been more lenient with our loading before the SSL bundle support was added.

In addition to that, you need to remove the following:

spring.ssl.bundle.jks.common.reload-on-update: true
spring.ssl.bundle.watch.file.quiet-period: 300s

You can only watch external files for changes, not those that are bundled in a jar.

Comment From: scottfrederick

I think the exception message that is given when reload-on-update is combined with classpath: resources could be more clear. I've opened #38903 to track that.