A standard configuration to enable Java to use the PKCS#11 HSM based keystore is not to configure anything to keystore path (keep it null) and configure the java security to get the PKCS 11 security provider. More information (with Sun/Oracle JVM) is available here. Java docs on Keystore specify - In order to create an empty keystore, or if the keystore cannot be initialized from a stream, pass null as the stream argument. (Ref: here) However doing so with Spring Boot results in following exception:
org.springframework.context.ApplicationContextException: Unable to start embedded container; nested exception is
java.lang.IllegalArgumentException: Resource location must not be null
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:133) ~[spring-boot-1.3.0.RELEASE.jar:1.3.0.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:531) ~[spring-context-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118) ~[spring-boot-1.3.0.RELEASE.jar:1.3.0.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752) ~[spring-boot-1.3.0.RELEASE.jar:1.3.0.RELEASE]
at org.springframework.boot.SpringApplication.doRun(SpringApplication.java:347) [spring-boot-1.3.0.RELEASE.jar:1.3.0.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:295) [spring-boot-1.3.0.RELEASE.jar:1.3.0.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1112) [spring-boot-1.3.0.RELEASE.jar:1.3.0.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1101) [spring-boot-1.3.0.RELEASE.jar:1.3.0.RELEASE]
at com.example.manager.ManagerApplication.main(ManagerApplication.java:27) [axon-manager-ws-0.3.2-SNAPSHOT.jar:0.3.2-SNAPSHOT] Caused by:
java.lang.IllegalArgumentException: Resource location must not be null
at org.springframework.util.Assert.notNull(Assert.java:115) ~[spring-core-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.util.ResourceUtils.getURL(ResourceUtils.java:131) ~[spring-core-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory.configureSslKeyStore(TomcatEmbeddedServletContainerFactory.java:329) ~[spring-boot-1.3.0.RELEASE.jar:1.3.0.RELEASE]
at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory.configureSsl(TomcatEmbeddedServletContainerFactory.java:312) ~[spring-boot-1.3.0.RELEASE.jar:1.3.0.RELEASE]
at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory.customizeSsl(TomcatEmbeddedServletContainerFactory.java:278) ~[spring-boot-1.3.0.RELEASE.jar:1.3.0.RELEASE]
at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory.customizeConnector(TomcatEmbeddedServletContainerFactory.java:257) ~[spring-boot-1.3.0.RELEASE.jar:1.3.0.RELEASE]
at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory.getEmbeddedServletContainer(TomcatEmbeddedServletContainerFactory.java:159) ~[spring-boot-1.3.0.RELEASE.jar:1.3.0.RELEASE]
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.createEmbeddedServletContainer(EmbeddedWebApplicationContext.java:158) ~[spring-boot-1.3.0.RELEASE.jar:1.3.0.RELEASE]
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:130) ~[spring-boot-1.3.0.RELEASE.jar:1.3.0.RELEASE]
... 8 more
It appears that the class "org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory" does not allow for Keystore path to be null. It attempts to load the resource from the given path.
The Spring Boot version is 1.3.0. I looked at the latest version, https://github.com/spring-projects/spring-boot/blob/master/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactory.java and the code does not seem to be changed (line 343) Interestingly enough, when the code attempt to load the Trust store, it is well protected (allows for null trust store path), see line 358.
It is a simple fix - to check if the keystore path is null and/or empty and let it be.
For anybody else looking to resolve this, the workaround exist - by overriding the "configureSsl" method of "org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory" and configuring this instance to be EmbeddedServletContainerFactory in the Application configuration.
The question is: Is there another way to configure the security / keystores in Spring Boot such that I wont need to override the TomcatEmbeddedServletContainerFactory? Or should I consider logging issue on Spring Boot and suggest a patch?