Tomcat java.io.IOException:通过Classloader加载keystore时的密钥库格式无效

时间:2015-06-23 01:27:25

标签: java spring tomcat keystore

我一直在努力找出这个问题。通过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)

1 个答案:

答案 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>