spring-projects / spring-boot

Spring Boot helps you to create Spring-powered, production-grade applications and services with absolute minimum fuss.
https://spring.io/projects/spring-boot
Apache License 2.0
75.38k stars 40.73k forks source link

Spring Boot 3.4.0: SslBundle cannot open store #43274

Open ibmmqmet opened 4 days ago

ibmmqmet commented 4 days ago

I am getting an exception with the SslBundles not being able to load the keystore. This worked fine with Spring Boot 3.3.6 (and previous levels). The file key.jks is in my current directory, from where the app is being run via gradle bootRun.

Configuration:

spring:
  jms:
    cache:
      enabled: true
  ssl:
    bundle:
      jks:
        ibmmq:
          truststore:
            location: "key.jks"
            password: "passw0rd"
            type: "JKS"
          keystore:
            location: "key.jks"
            password: "passw0rd"
            type: "JKS"

Exception stack:

Failed to instantiate [org.springframework.jms.connection.CachingConnectionFactory]: Factory method 'cachingJmsConnectionFactory' threw exception with message: Could not load SSL context: Unable to create key store: Could not load store from 'key.jks'
        at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:657)
        at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:645)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1351)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1181)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523)
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:336)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:288)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:334)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.instantiateSingleton(DefaultListableBeanFactory.java:1122)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingleton(DefaultListableBeanFactory.java:1093)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:1030)
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:987)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:627)
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752)
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:439)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:318)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1361)

with the root of the exception stack being

Caused by: java.lang.IllegalStateException: Could not load store from 'key.jks'
        at org.springframework.boot.ssl.jks.JksSslStoreBundle.loadKeyStore(JksSslStoreBundle.java:140)
        at org.springframework.boot.ssl.jks.JksSslStoreBundle.createKeyStore(JksSslStoreBundle.java:107)
        ... 39 common frames omitted
Caused by: java.io.FileNotFoundException: class path resource [key.jks] cannot be opened because it does not exist
        at org.springframework.core.io.ClassPathResource.getInputStream(ClassPathResource.java:215)
        at org.springframework.boot.ssl.jks.JksSslStoreBundle.loadKeyStore(JksSslStoreBundle.java:135)
        ... 40 common frames omitted
wilkinsona commented 3 days ago

Thanks for the report. It may be due to https://github.com/spring-projects/spring-boot/issues/42835, but I cannot be certain as the problem does not reproduce if I try to recreate what you've described above. Most likely because nothing's using the SSL bundle that you've configured.

By specifying only key.jks as the location, it's ambiguous how that resource should be loaded. An attempt is being made to load it using the classpath and this failed. That makes sense as, judging by what you have described, key.jks will not be on the classpath. You could try file:key.jks instead to make it clear that you want to load the store from the file system.

If the above does not help and/or you'd like us to spend some time investigating further, please spend some time providing a complete yet 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 up and attaching it to this issue.

ibmmqmet commented 3 days ago

Adding file: does get it to work. I don't remember seeing that syntax in the original docs, and I based it on finding other examples of using raw filenames for keystores in Spring Boot projects. But perhaps I missed this being different.

Thanks for the quick response.

wilkinsona commented 1 day ago

Thanks for confirming that it works with the file: prefix. I'm going to re-open this as I'd like us to look at whether we can restore the old behavior in this area and also keep the benefits of the recent changes around resource loading.

NYPD commented 1 day ago

I ran into a similar issue, but with a different error message:

***************************
APPLICATION FAILED TO START
***************************

Description:

The content of 'keystore.location' from bundle 'myBundle' is not watchable'. Only 'file:' resources are watchable, but '/usr/temp/certs/my-dev-keystore-pkcs12.p12' has been set

Action:

Update your application to correct the invalid configuration:
Either use a watchable resource, or disable bundle reloading by setting reload-on-update = false on the bundle.
spring.ssl.bundle.jks:
  myBundle:
    reload-on-updates: true
    keystore:
      location: /usr/temp/certs/my-dev-keystore-pkcs12.p12
      password: superSecretPassword
      type: "PKCS12"

Adding file: in front of my location worked as well.