I have a Java Spring service and I'm migrating a RestTemplate to a WebClient and spotted a problem with proxy (that's my guess).
Whole configuration is described here under my previous question here: Add additional parameter to the spring security oauth token request but I will copy paste it here again:
Project details:
spring-boot- 3.0.X
This is request required by customclient to get the token:
uri: xxxxxxx/token
{
"grant_type": "client_credentials",
"client_id": "xxxx",
"client_secret": "xxxxxxxx",
"account_id": "123456789"
}
application.yml
security:
oauth2:
client:
registration:
custom-client:
provider: custom-client
client-id: xxxxxxxxxxxxxxx
client-secret: xxxxxxxxxxxxxxx
authorization-grant-type: client_credentials
client-authentication-method: post
provider:
custom-client:
token-uri: xxxxxxxxxxxxxxxxxxxxxxxxxx/token
WebClientConfig.java
@Configuration
@Getter
@Setter
public class WebClientConfig {
@Bean
public OAuth2AuthorizedClientManager webclientManager(ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientService authorizedClientService) {
OAuth2AuthorizedClientProvider authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
.clientCredentials()
.build();
AuthorizedClientServiceOAuth2AuthorizedClientManager authorizedClientManager =
new AuthorizedClientServiceOAuth2AuthorizedClientManager(clientRegistrationRepository, authorizedClientService);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
@Bean
public WebClient customWebClient(@Qualifier("webclientManager") OAuth2AuthorizedClientManager authorizedClientManager) {
ServletOAuth2AuthorizedClientExchangeFilterFunction oAuth2Filer = new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
oAuth2Filer.setDefaultClientRegistrationId("customclient");
return WebClient.builder()
.filter(oAuth2Filer)
.baseUrl(apiUrl)
.build();
}
}
This is an example service where I would like to use webClient to make some REST call:
MyService.java
@Service
public class MyService{
WebClient webClient;
public MyService(@Qualifier("customClient") WebClient webClient) {
this.webClient = webClient;
}
public String testRequest() {
return webClient.get()
.uri("xxxxxx")
.retrieve()
.bodyToMono(String.class)
.block();
}
}
When I'm trying to test my code and make some REST call to other system using WebClient, I'm receiving following response:
"[invalid_token_response] An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: I/O error on POST request for "https:/xxxxxxxxxxxxxx/oauth2/token": A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond; nested exception is java.net.SocketException: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond"
I think it can be a problem with proxy and I've tried add something like this:
@Configuration
@Getter
@Setter
public class WebClientConfig {
@Bean
public OAuth2AuthorizedClientManager webclientManager(ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientService authorizedClientService) {
OAuth2AuthorizedClientProvider authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
.clientCredentials()
.build();
AuthorizedClientServiceOAuth2AuthorizedClientManager authorizedClientManager =
new AuthorizedClientServiceOAuth2AuthorizedClientManager(clientRegistrationRepository, authorizedClientService);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
@Bean
public WebClient customWebClient(@Qualifier("webclientManager") OAuth2AuthorizedClientManager authorizedClientManager,
final @Value("${proxy.url}" String proxyUrl,
final @Value("${proxy.port}" String proxyPort,
final @Value("${proxy.username}" String proxyUsername,
final @Value("${proxy.password}" String proxyPassword) {
ServletOAuth2AuthorizedClientExchangeFilterFunction oAuth2Filer = new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
oAuth2Filer.setDefaultClientRegistrationId("customclient");
Function<String, String> httpsProxyPassword = username -> proxyPassword;
HttpClient client = HttpClient.create()
.proxy(proxy -> proxy.type(ProxyProvider.Proxy.HTTP)
.host(proxyUrl)
.port(proxyPort)
.password(httpsProxyPassword)
.username(proxyUsername));
return WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(client))
.filter(oAuth2Filer)
.baseUrl(apiUrl)
.build();
}
}
But the repsonse is still the same.
After spending few hours debugging and trying multiple way, It turned out to be a problem with token request itself, which has to have proxy configured separately (in addition to the resource proxy config done within .clientConnector()) .
Examples here:
WebClient proxy configuration not working with oAuth2
https://blog.doubleslash.de/spring-oauth2-client-authorization-request-proxy-support