本来应该很简单的事情被证明是一场噩梦。我有两个 webapps - 第一个 (webapp1) 应该使用 RestTemplate 和密钥库中的 X509 证书发布到另一个 (webapp2),第二个 (webapp2) 过滤请求并检查 X509 证书的有效性这是信任库。
我在自定义 RestTemplate bean 中的 webapp1 中使用 ApacheHttp,如下所示:
@Bean
public RestTemplate restTemplate() {
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(this.httpClient());
RestTemplate restTemplate = new RestTemplate(factory);
restTemplate.getMessageConverters().add(0, new StringHttpMessageConverter(StandardCharsets.UTF_8));
restTemplate.getInterceptors().add(new RestTemplateHeaderModifierInterceptor());
restTemplate.setRequestFactory(factory);
return restTemplate;
}
public SSLConnectionSocketFactory sslConnectionSocketFactory() throws Exception {
return new SSLConnectionSocketFactory(sslContext(), NoopHostnameVerifier.INSTANCE);
}
@Bean
public HttpClient httpClient() throws Exception {
return HttpClientBuilder.create().setSSLSocketFactory(sslConnectionSocketFactory())
.addInterceptorFirst(new HttpComponentsMessageSender.RemoveSoapHeadersInterceptor()).build();
}
private SSLContext sslContext() throws Exception {
return SSLContextBuilder.create()
.loadKeyMaterial(resourceLoader.getResource(keyStorePath).getFile(), keyStorePassword.toCharArray(), keyStorePassword.toCharArray())
.loadTrustMaterial(resourceLoader.getResource(trustStorePath).getFile(), trustStorePassword.toCharArray())
.build();
}
在 webapp2 中,我使用 X509AuthenticationFilter 应该为我获取一个 PreAuthenticatedAuthenticationToken 然后可以通过以下方式访问:
SecurityContextHolder.getContext().getAuthentication()
唉,webapp2 说身份验证对象为空(当从邮递员使用正确的证书发布时,请求成功并且对象不为空),因此我无法从中提取 X509 证书以进行进一步验证。请求似乎没有到达 RestTemplate 应该通过 ApacheHttp 工厂附加的证书。当我在 RestTemplate.exchange(...) 之前调试代码时,我可以看到工厂有一个 HttpClient 对象,该对象包含一个 SSLSocketFactory,其中附加了来自指定密钥库的证书。
据我所知,这应该是开箱即用的,但似乎我遗漏了一块拼图。我已经用尽了许多代码重写,但都是徒劳的。我似乎无法确定 RestTemplate 的证书身份验证是如何工作的。有人能指出我正确的方向吗?
另外值得一提的是,webapp1 中的信任库部分有效(接收到 SSL 握手)。此外,密钥库和信任库均已正确加载并且其中的正确证书已被使用,我可以看到很多。