Spring RestTemplate call to HTTPS *without* HttpClient - spring-boot

Trying to make REST calls with RestTemplate using the server cert as the client cert to make calls with.
Don't ask me why :-), but I don't want to use Apache's HttpClient. I just think it's overkill.
I've seen code that uses regular JDK's SSLContext to set things up system-wide, i.e., set up SSLContext and the call SSLContext.setDefault(sslContext) as in this code:
// ... keymanagers, trustmanagers are omitted here
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keymanagers, trustmanagers, new SecureRandom());
SSLContext.setDefault(sslContext);
However, I saw a GitHub comment here (https://github.com/spring-projects/spring-boot/issues/6493) that states that setting SSLContext as default like that isn't really a good idea.
So, my question is: outside of having to use HttpClient, is there a way to use the sslContext configured in the code snippet above in RestTemplate setup somehow?

You can override the default requestFactory in the restTemplate by doing
restTemplate.setRequestFactory(new MyCustomRequestFactory());
Have a look at org.springframework.http.client.SkipSslVerificationHttpRequestFactory here for an example of setting SSLContext in your request factory.

Related

Spring Gateway - multiple httpclients in Spring Gateway?

I have many filters that I use to manipulate different requests.
I'm overriding the default netty httpClient provided by Spring Gateway so I can set programatically some sslContext - mTLS in my case. This is fine, but I will also need to have a second netty httpClient so I can connect to other server with no ssl at all, or just regular tls.
I was wondering if it's possible either to set sslContext on specific filters or to decide what httpClient to use based on the filter or some other extension point that spring gateway provides.
Do you think it is possible to have multiple httpClients and decide which one to use?
I tried to create a new bean which configures a httpClient and set some sslContext like this:
#Bean
public reactor.netty.http.client.HttpClient httpClient() {
final PrivateKey privateKey = getPrivateKey();
final X509Certificate x509Certificate = getX509Certificate();
final SslContext sslContext =
SslContextBuilder.forClient()
.trustManager(InsecureTrustManagerFactory.INSTANCE)
.keyManager(privateKey, x509Certificate)
.build();
return reactor.netty.http.client.HttpClient.create().secure(sslContextSpec -> sslContextSpec.sslContext(sslContext));
}
While I use this httpClient to connect via mTLS it works fine, but I'd like to decide what httpClient to use based on specific filters.

Does calling https service by Resttemplate work for all services whose certificate has been imported in the trustore of my client service?

I have a restemplate which can make call to multiple external systems over https.
I configured the resttemplate like so :
SSLContext sslContext = SSLContextBuilder
.create()
.loadTrustMaterial(key, keyPassword)
.build();
HttpClient client = HttpClients
.custom()
.setSSLContext(sslContext)
.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
.build();
HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(
client);
httpComponentsClientHttpRequestFactory.setConnectTimeout(5000);
httpComponentsClientHttpRequestFactory.setReadTimeout(30000);
return new RestTemplate(httpComponentsClientHttpRequestFactory);
I have setup 2 mock services on 2 separate VMs with ssl enabled and I am testing this restemplate by calling those services over https. And it works.
What I want to confirm is that configuring the restemplate as shown in the above code and importing the certificates of the different services to be called in by the client truststore should work without any additional configurations right?
I am confused because in the code in this example here : https://github.com/jonashackt/spring-boot-rest-clientcertificates-docker-compose the author has used 2 different factories i.e. serverTomClientHttpRequestFactory & serverAliceClientHttpRequestFactory, however mine works with a single restemplate. can someone please shed some light on this topic?

Apache HttpClient for RestTemplate default behaviour if not setting up SSLSocketFactory and SSLContext

I am using Spring RestTemplate (config using HttpClient) to make a restful service call for a URL with https.
I explicitly setup SSL using following code:
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial().setProtocol().build
return new SSLConnectionSocketFactory(sslContext)
It works without any problem.
What would be the default behaviour if I don't setup SSLSocketFactory and SSLContext for HttpClient? Will it look for the cacerts under the installed JDK or it will disable the ssl?
I say Yes If your https website can be passed by your browser, or your certificate file is coming from the Certificate Authority such as GlobalSign, Verisign
we can see the SSLContext and SSLSocketFactory will be created automatically, so you can visit https without doing anything
if your certificate file is not trusted, and import to jdk cacerts still can't solve this, because HttpClient download the certificate file via SSLSocket, not from the jdk cacerts

InterceptingAsyncClientHttpRequestFactory Use

I was trying to understand the use of InterceptingAsyncClientHttpRequestFactory. When run test with MockRestServiceServer I saw requestFactory is decorated with this ResquestFactory. Is there any other use of this requestFactory? Basically I want to know the idea behind InterceptingAsyncClientHttpRequestFactory. As I couldn't find any examples to use it.
Below code doesn't work.
AsyncClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsAsyncClientHttpRequestFactory(
httpAsyncClient);
List<AsyncClientHttpRequestInterceptor> interceptors = new ArrayList<>(1);
interceptors.add(asyncRestReqResInterceptor());
AsyncClientHttpRequestFactory interceptorFactory = new InterceptingAsyncClientHttpRequestFactory(
clientHttpRequestFactory, interceptors);
AsyncRestTemplate asyncRestTemplate = new AsyncRestTemplate(interceptorFactory);
Please let me know the correct implementation.
The general idea behind request factory is that you can customize how HttpAccessor implementations, like RestTemplate, makes requests. If you don't specify anything you get non-pooled HttpURLConnection, but spring offers factories for Appache HttpClient and other 3rd part libraries.
InterceptingAsyncClientHttpRequestFactory is a decorator, which allows you to plug-in Interceptors that modify the request befor it is sent. One such Interceptor is the BasicAuthorizationInterceptor which adds the Authorization header to every request. If you have stuff you need to do to every request you can create your own ClientHttpRequestInterceptor.

RestTemplate logging POST data

my resttemplate.exchange() failed on a POST request, with the server returning a 500 error.
I tried to set the root logging level to DEBUG, but nothing was logged before the 500 error was returned. to make sure that my logging config is right, I added a line before the resttemplate call
HttpClient client = new DefaultHttpClient();
client.execute(new HttpGet("http://google.com"));
in this case indeed a lot of logging messages appeared.
so how can I make RestTemplate export the debugging data?
Thanks
Yang
From your analysis it seems that you expect RestTemplate to use Apache HttpClient.
However, by default, Spring RestTemplate does not use Apache HttpClient but uses the JDK facilities (java.net.URL#openConnection() etc.) by means of SimpleClientHttpRequestFactory.
org.springframework.http.client.support.HttpAccessor declares:
private ClientHttpRequestFactory requestFactory = new
SimpleClientHttpRequestFactory();
As far as I know, this client does not support logging requests/responses.
To change RestTemplate to use HttpClient, try this:
new RestTemplate(new HttpComponentsClientHttpRequestFactory());
Logging configuration should then enable category org.apache.http.wire at level debug for complete requests/responses to be logged.

Resources