-
Notifications
You must be signed in to change notification settings - Fork 6.1k
ServletOAuth2AuthorizedClientExchangeFilterFunction supports chaining #6526
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
Conversation
@rwinch A couple of things for you to consider during the review.
|
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.
I provided feedback inline. We also need some tests added.
.map(authorizedClient -> bearer(request, authorizedClient)) | ||
.flatMap(next::exchange) | ||
.switchIfEmpty(next.exchange(request)); | ||
if (!attribute.isPresent()) { |
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 code is the same as the else block. It should be able to be restructured like: try and get the authorized client, if not there default it, process (same process in either case).
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.
Applied in latest commit
.map(ClientRequest.Builder::build); | ||
} | ||
|
||
private void populateRequestAttributes(Map<String, Object> attrs, Context ctx) { |
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.
Do we want Context
to override potentially existing attrs
?
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.
I original had attrs.putIfAbsent()
but didn't see any reason for it. Do you anticipate a potential issue with overriding? The attributes in the Context
will always be what the filter needs so I don't see any issue with this. What do you think?
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.
Applied putIfAbsent()
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.
My concern was if someone had a custom Authentication
they were working with, it might be explicitly set as an attribute. Perhaps this is so that a global access token is used for client_credentials access tokens.
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.
I see. Ok so putIfAbsent()
is needed...and it was updated in latest commit
@@ -169,9 +176,23 @@ public void setDefaultClientRegistrationId(String clientRegistrationId) { | |||
* @return the {@link Consumer} to configure the builder | |||
*/ | |||
public Consumer<WebClient.Builder> oauth2Configuration() { | |||
Hooks.onLastOperator(REQUEST_CONTEXT_OPERATOR_KEY, Operators.lift((s, sub) -> createRequestContextSubscriber(sub))); |
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 can make this implement DisposableBean to clean up the hooks
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.
Not sure I understand? The ExchangeFilterFunction
would not really be a @Bean
. The WebClient
would be but that's not always the case either. What were you thinking exactly?
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 need a way to clean up the Hooks and a DisposableBean makes a lot of sense for that reason. Why wouldn't/couldn't it be a Bean? How would you clean it up?
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.
I agree DisposableBean
is an option and yes we need to cleanup/release the Hook. I just don't understand who would be responsible for registering the ExchangeFilterFunction
as a @Bean
? Would this be required by the user to register? What if they don't register it? Am I missing something from what you are suggesting?
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 user is already in charge of creating the ExchangeFilterFunction
and registering it with the WebClient
. This just means they should create it as a Bean
.
If they forget, then it is the same problem as any other DisposableBean
that they didn't register as a Bean. Things end up in an inconsistent state. This scenario is really more important when the JVM process runs longer than the ApplicationContext (i.e. tests) I doubt it will cause a lot of issues, but it is not semantically correct to leave the Hook registered.
If you don't think DisposableBean is a good idea, what do you think we should do to ensure it gets cleaned up?
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 just means they should create it as a
Bean
.
As a user I would question why do I need to register it as a @Bean
?
then it is the same problem as any other
DisposableBean
that they didn't register as a Bean
Yes but if the user is registering a user-defined @Bean
and they have implemented a cleanup/release of resources than they know why they need to register it as a @Bean
. With the ExchangeFilterFunction
, the framework is doing the cleanup so it's not as obvious to them that they need to register it. It will have to be well documented so it's not missed.
it is not semantically correct to leave the Hook registered.
Agreed, or else the Context
will contain the request attributes for every sequence created which is not good.
We need to do something for sure. I'm thinking PreDestroy
instead of DisposableBean
since the framework recommends this approach as well. What do you think?
Merged via 0c27f64 |
if (context.hasKey(CONTEXT_DEFAULTED_ATTR_NAME)) { | ||
return context; | ||
} | ||
return Context.of( |
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 @rwinch
This subscriber applies for each reactive chain by Hooks.onLastOperator() globally
Context does not alllow null values (see reactor/reactor-core#1800)
what if Mono.subscribe()/block() is executed out of security or web context (rabbitmq listener or just some scheduled task...)?
if (context.hasKey(CONTEXT_DEFAULTED_ATTR_NAME)) { | ||
return context; | ||
} | ||
return Context.of( |
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.
Context javadoc states
* Note that contexts are optimized for low cardinality key/value storage, and a user
* might want to associate a dedicated mutable structure to a single key to represent his
* own context instead of using multiple {@link #put}, which could be more costly.
* Past five user key/value pair, the {@link Context} will use a copy-on-write
* implementation backed by a new {@link java.util.Map} on each {@link #put}.
but this subscriber creates 4 keys (occupies almost all "optimmized" implementations of Context)
and as far as I understand CONTEXT_DEFAULTED_ATTR_NAME
key is just a marker
Maybe it would be better to put all this attrs into some holder so you can reduce number of keys from 4 to 1. And it allows remove extra CONTEXT_DEFAULTED_ATTR_NAME
I mean that it is not just spring security who populates context and it could impact overall performance if context is populated by other libraries frequently
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 Thanks for the report. Can you create a ticket or a a PR for this?
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.
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.
and here is PR #7235
Fixes gh-6483