Reputation: 408
I'm struggeling to correctly setup the webflux-weblient with oauth2 behind a proxy.
It seems, that the ServerOAuth2AuthorizedClientExchangeFilterFunction uses a new instance of a webclient , which doesn't contain my proxy-configuration.
OAuth2-Config
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth2ClientFilter = new ServerOAuth2AuthorizedClientExchangeFilterFunction(
clientRegistrations,
new UnAuthenticatedServerOAuth2AuthorizedClientRepository());
oauth2ClientFilter.setDefaultClientRegistrationId("azure");
OAuth2AuthorizedClientResolver.class contains:
private ReactiveOAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> clientCredentialsTokenResponseClient = new WebClientReactiveClientCredentialsTokenResponseClient();
The WebClientReactiveClientCredentialsTokenResponseClient.java
creates a new webclient as follows:
private WebClient webClient = WebClient.builder().build();
Does anybody have a sample how to correctly setup a http-proxy for the oauth2 client?
Upvotes: 4
Views: 3458
Reputation: 358
Thanks to the incomplete answer of @abhinaba-chakraborty, I managed to set proxy based on the JVM params inside the WebClient
for WebClientReactiveClientCredentialsTokenResponseClient
.
Here is my pieces of code to help other people with the same issue :
This is a helper function to take the JVM params and set them to the HttpClient
public HttpClient proxyHttpClient() {
String proxyHost = System.getProperty("https.proxyHost");
String proxyPort = System.getProperty("https.proxyPort");
if (proxyHost == null && proxyPort == null) {
return HttpClient.create();
}
return HttpClient.create()
.tcpConfiguration(tcpClient ->
tcpClient.proxy(proxy ->
proxy.type(ProxyProvider.Proxy.HTTP).host(proxyHost).port(Integer.valueOf(proxyPort))
)
);
}
This is how to configure the OAuth2Client for the WebClient
used for calling outside systems (based on the response of @abhinaba-chakraborty). Note the function named configureHttpProxy
:
@Bean
public ReactiveOAuth2AuthorizedClientManager authorizedClientManager(
ReactiveClientRegistrationRepository clientRegistrationRepository,
ReactiveOAuth2AuthorizedClientService authorizedClientService) {
return configureHttpProxy(
new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(
clientRegistrationRepository,
authorizedClientService
)
);
}
@Bean
WebClient webClient(ReactiveOAuth2AuthorizedClientManager authorizedClientManager) {
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth2Client = new ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
oauth2Client.setDefaultClientRegistrationId("registration_id");
return WebClient.builder()
.filter(oauth2Client)
.clientConnector(new ReactorClientHttpConnector(HttpClient.create().wiretap(true)))
.baseUrl(rdoWebClientProperties.getBaseUrl())
.defaultHeader(rdoWebClientProperties.getApikeyName(), rdoWebClientProperties.getApikeyValue())
.build();
}
And here is the configureHttpProxy
function:
private AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager configureHttpProxy(AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager authorizedClientManager) {
// set the webclient with proxy configuration in the ReactiveOAuth2AccessTokenResponseClient
WebClientReactiveClientCredentialsTokenResponseClient tokenResponseClient = new WebClientReactiveClientCredentialsTokenResponseClient();
tokenResponseClient.setWebClient(
WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(proxyHttpClient()))
.build()
);
// set the ReactiveOAuth2AccessTokenResponseClient with webclient configuration in the ReactiveOAuth2AuthorizedClientProvider
ClientCredentialsReactiveOAuth2AuthorizedClientProvider authorizedClientProvider = new ClientCredentialsReactiveOAuth2AuthorizedClientProvider();
authorizedClientProvider.setAccessTokenResponseClient(tokenResponseClient);
// set the ReactiveOAuth2AuthorizedClientProvider in the ReactiveOAuth2AuthorizedClientManager
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
Hoping this will help.
Upvotes: 6
Reputation: 3671
For OAuth2.0 Client Credentials flow, in the websecurity configuration, you need something like:
@EnableWebFluxSecurity
public class WebSecurityConfiguration {
@Bean
public ReactiveOAuth2AuthorizedClientManager authorizedClientManager(
ReactiveClientRegistrationRepository clientRegistrationRepository,
ReactiveOAuth2AuthorizedClientService authorizedClientService) {
ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider =
ReactiveOAuth2AuthorizedClientProviderBuilder.builder()
.clientCredentials()
.build();
AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager authorizedClientManager =
new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientService);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
@Bean
public WebClient webClient(ReactiveOAuth2AuthorizedClientManager authorizedClientManager) {
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth =new ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
return WebClient.builder().filter(oauth).build();
}
}
Now to make an actual API call:
webClient.get()
.uri(<protected resource uri which you want to access>)
.attributes(clientRegistrationId(<The Provider name specified under registration in app yaml>))
.retrieve()
.bodyToMono(String.class)
.map(string
-> "Retrieved using Client Credentials Grant Type: " + string)
.subscribe(LOGGER::info);
For your reference I am using the Spring Boot version 2.3.1.RELEASE And my application.yaml looks like this:
spring:
security:
oauth2:
client:
provider:
<provider-name>:
issuer-uri: <issuer-uri implementing OIDC>
registration:
<provider-name>:
client-id: <client-id>
client-secret: <client-secret>
scope: <comma separated scopes>
authorization-grant-type: client_credentials
Upvotes: 0