I am struggling with what seems to be a trivial problem, but I cannot get my head around it. So here it is.
I am working on a project that involves a bunch of microservices deployed on Openshift. Each microservice is built with Spring-Boot 2.1.4. We deploy the .war in a docker Tomcat 9 container. I have no access to the configuration of these containers.
As of now, we removed all the spring-security dependencies to debug the problem more easily.
In one of the microservices, we need to retrieve data from a 3rd party source via a GET method. So we use a RestTemplate.
We implemented a GET method towards a test endpoint (http) to the 3rd party service. It works flawlessly. Now we have been given a pre-prod endpoint which uses SSL, so we had to convert our GET implementation for the use of SSL.
We have been given a certificate ".crt". Here are the tests I carried out, that I hope can shed some light.
From the terminal of the Openshift POD, I was able to make successful curl GET calls towards the target https endpoint, in particular:
From this information I guessed that the certificate is used to validate the server and not for authentication (I may be totally wrong, mind you. This is the first time I am dealing with this subjects...). So I created a "trustStore.jks" with the Java keytool by importing the certificate ".crt".
I imported the truststore in my spring boot project and configured the RestTemplate to use it, by using one of the guides that you can easily find online, they seem to be all pretty similar [I used this one: https://www.baeldung.com/spring-boot-https-self-signed-certificate].
The result is something like this:
.....
File trustfile = new File(
WebServiceUtils.class
.getClassLoader().getResource("truststore.jks").getFile()
);
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(endpoint);
String trustStorePath = trustfile.getAbsolutePath();
SSLContext sslContext = new SSLContextBuilder()
.loadTrustMaterial(ResourceUtils.getFile(trustStorePath),
"mypassword".toCharArray())
.build();
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext);
HttpClient client = HttpClients.custom()
.setSSLSocketFactory(socketFactory)
.build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(client);
RestTemplate restTemplate = new RestTemplate(requestFactory);
HttpEntity entity = new HttpEntity(httpHeaders);
ResponseEntity<T> respEntity = restTemplate.exchange(builder.toUriString(),
HttpMethod.GET,
entity,
in);
return respEntity.getBody();
The problem is that I keep getting a connect timeout and I cannot understand how to solve this problem. The error is:
org.springframework.web.client.ResourceAccessException: I/O error on GET request for "myHttpsEndpoint": Connect to myHttpsEndpoint failed: Connection timed out (Connection timed out); nested exception is org.apache.http.conn.HttpHostConnectException: Connect to myHttpsEndpoint failed: Connection timed out (Connection timed out)
Now, I am sure the keystore gets at least read correctly since, if I purposely insert a wrong password, it warns me. I tried many tweaks that I found here on StackOverflow without success. What puzzles me the most is that despite all my tests, the error never changes. It gets stuck always there.
This lead me to believe that I may be blocked by something else, a firewall of some kind. I am guessing, I may be wrong obviously. And even if that was the case, I cannot even explain why from curl, in the pod terminal, it works.
It also works if I use the GET method without SSL with the pre-prod https endpoint (the GET method that I was using against the test endpoint, the one written for the http endpoint).
I would like to have an expert opinion from you. Can it be a configuration-related error not in my control?
Thank you very much!