Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
4.5k views
in Technique[技术] by (71.8m points)

java - RestTemplate X509 Certificate as authentication when sending request

Something that was supposed to be simple is proving to be a nightmare. I have two webapps - the first (webapp1) should post to the other (webapp2) with the use of RestTemplate and a X509 certificate in the keystore, and the second one (webapp2) filters the request and checks the validity of the X509 certificate in it's truststore.

I'm using ApacheHttp in webapp1 in a custom RestTemplate bean as follows:

@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();
}

In webapp2, I use a X509AuthenticationFilter that should fetch me a PreAuthenticatedAuthenticationToken which can then be accessed through:

SecurityContextHolder.getContext().getAuthentication()

Alas, webapp2 says the authentication object is null (when posted from Postman with the correct certificate, the request succeeds and the object is not null), therefore I cannot extract a X509 certificate from it for further validation. The request seems to arrive without the certificate that the RestTemplate should append through the ApacheHttp factory. When I debug the code before RestTemplate.exchange(...), I can see the factory has a HttpClient object that contains an SSLSocketFactory with a credentialsMap where the certificate from the specified keystore is appended.

As far as I'm aware, this should be working out of the box, but it seems like I'm missing a piece of the puzzle. I've exhausted a number of code rewrites, but in vain. I can't seem to pinpoint how certificate authentication with RestTemplate works. Can someone point me in the right direction?

Also worth mentioning, the truststore part in webapp1 works (an SSL handshake is received). Also also, both the keystore and truststore are loaded correctly and the correct certs in them are consumed, I can see as much.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
等待大神解答

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...