-
Notifications
You must be signed in to change notification settings - Fork 5.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce Reactive OAuth2AuthorizedClient Manager/Provider #7116
Introduce Reactive OAuth2AuthorizedClient Manager/Provider #7116
Conversation
3d0fd4d
to
1e7e4bd
Compare
@rwinch @jzheaux I just merged #6845 and rebased this PR off master. As an FYI, all the review feedback from #6845 has also been applied to this PR. I believe this is close to merging. It would be ideal if we can merge this for M4 as well. Feel free to add polish in order to get this merged while I am away. Thank you. |
1e7e4bd
to
d5e4325
Compare
OAuth2Error oauth2Error = new OAuth2Error(INVALID_TOKEN_RESPONSE_ERROR_CODE, | ||
"An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: " + | ||
"HTTP Status Code " + response.rawStatusCode(), null); | ||
throw new OAuth2AuthorizationException(oauth2Error); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
possible resource leak
from org.springframework.web.reactive.function.client.WebClient.RequestHeadersSpec#exchange javadoc
NOTE: You must always use one of the body or entity methods of the response to ensure resources are released. See ClientResponse for more details.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@robotmrv I'm not sure I'm following? The ClientResponse.body
method is used for a successful response...
response.body(oauth2AccessTokenResponse())
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ClientResponse.body method is used for a successful response...
exactly
it is requirement to consume body in any case
there are several issues related to this problem (e.g. spring-projects/spring-framework#22005 (comment) )
see last paragraph from reference guide https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-client-exchange
So my proposal is just to use in case of error
return clientResponse.bodyToMono(Void.class)
.then(Mono.error(new OAuth2AuthorizationException(oauth2Error)));
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for catching this @robotmrv. I'll update similar to your proposal.
...mework/security/oauth2/client/endpoint/WebClientReactiveRefreshTokenTokenResponseClient.java
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR @jgrandja! I have provided feedback inline
...ramework/security/oauth2/client/AuthorizationCodeReactiveOAuth2AuthorizedClientProvider.java
Outdated
Show resolved
Hide resolved
} | ||
|
||
private boolean hasTokenExpired(AbstractOAuth2Token token) { | ||
return token.getExpiresAt().isBefore(Instant.now().minus(this.clockSkew)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably allow injecting a Clock vs using Instant.now. This comment should be applied globally throughout this PR. Additionally, we should do the same on the imperative side
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This enhancement is tracked in this ticket #7114
...th2/client/web/reactive/result/method/annotation/OAuth2AuthorizedClientArgumentResolver.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.body(tokenRequestBody(refreshTokenGrantRequest)) | ||
.exchange() | ||
.flatMap(response -> { | ||
if (!response.statusCode().is2xxSuccessful()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is possible to catch IllegalArgumentException for non-standard status code
Not sure about real probability of the problem but
there are several related issues
spring-cloud/spring-cloud-sleuth#1382
spring-projects/spring-framework#23367
spring-projects/spring-framework#23366
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @robotmrv You are right we need to ensure we don't cause a leak by calling statusCode()
when the status is unknown. Instead we should do something like:
HttpStatus status = HttpStatus.resolve(response.rawStatusCode());
if (status == null || !status.is2xxSuccessful()) {
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jgrandja I see that this case was not covered in your final commit.
Just check that You did not miss it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR addresses the reactive implementation of #6811.