我一直在努力找出这个问题。通过Tomcat上的Classloader加载密钥库时,我一直收到无效的密钥库格式错误。我已经编写了一些单元测试,这些测试通过类路径加载我的密钥库是成功的,但是当在Tomcat中运行时,我得到了无效的密钥库格式错误。
这适用于RestTemplate Spring REST客户端。
我的Spring配置代码......在单元测试和真实配置中几乎相同。
@Value("${env}")
private String env;
@Bean
public RestTemplate getRestTemplate(HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory) {
return new RestTemplate(httpComponentsClientHttpRequestFactory);
}
@Bean
public HttpComponentsClientHttpRequestFactory getHttpComponentsClientHttpRequestFactory(HttpClient httpClient) {
HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
return httpComponentsClientHttpRequestFactory;
}
@Bean
public HttpClientConnectionManager getHttpClientConnectionManager() throws Exception {
String password = environment.getProperty("keystore.password");
InputStream cpStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(env + "/keystore.jks");
//load the keystore
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(cpStream, password.toCharArray());
SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(keystore).build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
PlainConnectionSocketFactory plainsf = PlainConnectionSocketFactory.getSocketFactory();
Registry<ConnectionSocketFactory> r = RegistryBuilder.<ConnectionSocketFactory>create().register("http",plainsf).register("https",sslsf).build();
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(r);
cm.setMaxTotal(200);
cm.setDefaultMaxPerRoute(50);
return cm;
}
@Bean
public HttpClient getHttpClient(HttpClientConnectionManager httpClientConnectionManager) {
return HttpClients.custom().setConnectionManager(httpClientConnectionManager).build();
}
此代码可以在我的单元测试中使用我RestTemplate
所需的密钥库创建SSLContext
。我也尝试过通过单元测试从类加载器中获取我的密钥库的InputStream的不同方法,这些方法也都有效。
InputStream cpStream = this.getClass().getClassLoader().getResourceAsStream(env + "/csaa.jks");
InputStream cpStream = this.getClass().getResourceAsStream("/" + env + "/csaa.jks");
env
变量只是一种加载特定环境属性的方法... env = DEV等......使用JUnit SpringJUnit4ClassRunner.class
运行它时一切正常但是在部署它时Tomcat我总是得到无效的密钥库错误。如果我使用带有硬编码路径的FileInputStream
到文件系统上的密钥库,它在Tomcat中运行正常。我真的想用Classloader加载它。
我也在Liberty Profile中尝试了相同的结果。
堆栈跟踪的相关部分:
Caused by: java.io.IOException: Invalid keystore format
at sun.security.provider.JavaKeyStore.engineLoad(JavaKeyStore.java:650)
at sun.security.provider.JavaKeyStore$JKS.engineLoad(JavaKeyStore.java:55)
at java.security.KeyStore.load(KeyStore.java:1445)
答案 0 :(得分:12)
我发现了我的问题......我的Maven过滤破坏了密钥库。我需要将以下内容添加到我的pom.xml中。可悲的是,我不认为这是我第一次遇到这个问题。 :(
的pom.xml:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*.xml</include>
</includes>
<excludes>
<exclude>**/*.jks</exclude>
</excludes>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
<includes>
<include>**/*.jks</include>
</includes>
<excludes>
<exclude>**/*.xml</exclude>
</excludes>
</resource>
</resources>