I'm having a wierd issue while migrating API calls from an old webapp from our previous API management to Apigee (GCP API management tool). I'm not even sure that the fact I'm trying to call Apigee is an issue itself but still I'm mentioning it for the sake of completeness.
Here is how the RestTemplate is configured
@Bean
public RestTemplatemyRestTemplate(
RestTemplateBuilder restTemplateBuilder,
@Value("${application.my.url}") String myUrl,
Supplier<ClientHttpRequestFactory> bufferingClientHttpRequestFactorySupplier,
OAuth2TokenService oAuth2TokenService
) {
return restTemplateBuilder
.rootUri(myUrl)
.requestFactory(bufferingClientHttpRequestFactorySupplier)
.interceptors(new AuthorizationHeaderInterceptor(oAuth2TokenService)) // Oauth2 mechanism that is working well
.build();
}
Now this is where the API call is done
public void createOrUpdateCustomerSource(Customer myCustomer, final HttpHeaders headers) throws TechnicalException {
final HttpEntity<Customer> httpEntity = new HttpEntity<>(myCustomer, headers);
final String myId = "dummyId";
final String uri = UriComponentsBuilder
.newInstance()
.pathSegment("some-path", myId))
.build().toString();
try {
log.info("Sending PUT request for customer Id: {} at {}", myId, uri);
myRestTemplate.exchange(uri, HttpMethod.PUT, httpEntity, Void.class);
} catch (RestClientException e) {
// exception handling
}
}
This is quite basic I would say but for some reason I'm getting this output from the resttemplate :
org.springframework.web.client.HttpClientErrorException$NotFound: 404 Not Found: [no body]
Nothing reaches Apigee except the call to retrieve the authorization token. Obvisouly I've tried to copy paste the exact same URL used by the RestTemplate on Postman and it works well since I can monitor that with Apigee.
One last thing I need to add is that if I call my API like that (without any body nor header) : myRestTemplate.exchange(uri, HttpMethod.PUT, null, Void.class); it DOES reach Apigee, which leads me to think that my way to do a PUT is wrong and I don't know why.
Alright I found the issue and the culprit was inside the headers that were sent during the external API call. For some reason this WS is forwarding the exact same headers received when it's called during the external API call, and one of them was host.
As described in this Stackoverflow post or in this blog post, this header allows the recipient to know where does the request comes from. And in our case, my application is hosted in the cloud somewhere, and Apigee is in GCP somewhere else. Forwarding the host header results in Apigee receiving a request with an invalid host that can't be validated. Setting the proper headers I need to trasnmit to my external API resolved the problem.
As quoted:
Depending on your configuration type, there are different ways you can prevent host header injections. Of course, the most straightforward approach is to distrust the host header at all times and not use it in server-side code. This simple change can essentially eliminate the possibility of a host header attack being launched against you.