-
Notifications
You must be signed in to change notification settings - Fork 6k
Add support for customizing the Access Token Request #5656
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
Add support for customizing the Access Token Request #5656
Conversation
} | ||
|
||
@Override | ||
public OAuth2AccessTokenResponse getTokenResponse(T authorizationGrantRequest) throws OAuth2AuthenticationException { |
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.
Rename parameter authorizationGrantRequest
to accessTokenRequest
and mark it final
At a high level, I don't really like the idea of the I propose the code be refactored to be exposed using the existing APIs within RestTemplate. The DefaultClientCredentialsTokenResponseClient and DefaultAuthorizationCodeTokenResponseClient can then use a RestTemplate with the appropriate API implementations registered by default. User's would then be required to provide a RestOperations implementation that can convert from a request/response to the OAuth2AccessTokenResponseClient. Note that proper setup of the RestTempalte is already required since the AbstractOAuth2AccessTokenResponseClient relies on a NoOpResponseErrorHandler being set to handle the errors. As it stands the user cannot inject a custom RestOperations and expect this to work without creating their own NoOpResponseErrorHandler. |
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.
Please see #5656 (comment)
@rwinch Ok this makes sense as far as leveraging Can you clarify:
I can't seem to find |
Sorry that was a typo. I meant to type buildRequest method. To be clear...I'm not certain which pieces of RestOperations/RestTemplate make the most sense for us to leverage. What seems clear to me is that there are enough APIs for us to leverage within RestTemplate already. |
* @param authorizationGrantType the authorization grant type | ||
* @param clientRegistration the client registration | ||
*/ | ||
protected AbstractOAuth2AuthorizationGrantRequest( |
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.
Is this change necessary for this PR? I'm not sure it adds a lot especially with the value being optional vs in subclasses we know it is non-null. At minimum, I'd like to consider this change separately if possible.
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.
Agreed this change can be removed
import org.springframework.http.ResponseEntity; | ||
import org.springframework.http.client.ClientHttpResponse; | ||
import org.springframework.http.converter.FormHttpMessageConverter; | ||
import org.springframework.security.oauth2.client.endpoint.converter.OAuth2AuthorizationCodeGrantRequestEntityConverter; |
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 is a package tangle because a parent package is accessing a subpackage of itself.
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'm wondering if to fix the tangle if we could move OAuth2AuthorizationCodeGrantRequestEntityConverter
and OAuth2ClientCredentialsGrantRequestEntityConverter
to org.springframework.security.oauth2.core.http.converter
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.
OAuth2AuthorizationCodeGrantRequest
and OAuth2ClientCredentialsGrantRequest
reside in the client.endpoint
package so we should keep it in the client
module.
The 2 options I can think of right now are:
org.springframework.security.oauth2.client.endpoint
(keep in same package)
org.springframework.security.oauth2.client.converter
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.
Good point, I think given it is associated with RequestEntity, we should consider a variation of what you proposed. What do you think of org.springframework.security.oauth2.client.http.converter
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.
Agreed that makes sense....let's go with org.springframework.security.oauth2.client.http.converter
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.1.3">Section 4.1.3 Access Token Request (Authorization Code Grant)</a> | ||
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.1.4">Section 4.1.4 Access Token Response (Authorization Code Grant)</a> | ||
*/ | ||
public class DefaultAuthorizationCodeTokenResponseClient implements OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> { |
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.
Most of the methods are already final, let's make the class final
* | ||
* @param restOperations the {@link RestOperations} used when requesting the access token response | ||
* @param restOperations the {@link RestOperations} used when requesting the Access Token Response | ||
*/ | ||
public final void setRestOperations(RestOperations restOperations) { |
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.
How can someone inject the RestOperations and still get valid error handling? I think we may need to make OAuth2ErrorResponseErrorHandler public.
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 document what the RestOperations required (i.e. the types of converters it would need, error handling, etc)
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 was thinking of exposing OAuth2ErrorResponseErrorHandler
but the implementation was pretty easy so decided to hide it.
Either way, I'm fine with exposing it.
* @param authorizationCodeGrantRequest the authorization code grant request | ||
* @return the {@link HttpHeaders} used for the Access Token Request | ||
*/ | ||
protected HttpHeaders buildHeaders(OAuth2AuthorizationCodeGrantRequest authorizationCodeGrantRequest) { |
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'd like this to be private. User's that need to customize the headers can do so by delegation to this class and constructing a modified RequestEntity.
* @param authorizationCodeGrantRequest the authorization code grant request | ||
* @return a {@link MultiValueMap} of the form parameters used for the Access Token Request body | ||
*/ | ||
protected MultiValueMap<String, String> buildFormParameters(OAuth2AuthorizationCodeGrantRequest authorizationCodeGrantRequest) { |
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'd like this to be private. User's that need to customize the headers can do so by delegation to this class and constructing a modified RequestEntity.
* @param clientCredentialsGrantRequest the client credentials grant request | ||
* @return the {@link HttpHeaders} used for the Access Token Request | ||
*/ | ||
protected HttpHeaders buildHeaders(OAuth2ClientCredentialsGrantRequest clientCredentialsGrantRequest) { |
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'd like this to be private. User's that need to customize the headers can do so by delegation to this class and constructing a modified RequestEntity.
* @param clientCredentialsGrantRequest the client credentials grant request | ||
* @return a {@link MultiValueMap} of the form parameters used for the Access Token Request body | ||
*/ | ||
protected MultiValueMap<String, String> buildFormParameters(OAuth2ClientCredentialsGrantRequest clientCredentialsGrantRequest) { |
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'd like this to be private. User's that need to customize the headers can do so by delegation to this class and constructing a modified RequestEntity.
* | ||
* @param restOperations the {@link RestOperations} used when requesting the access token response | ||
* @param restOperations the {@link RestOperations} used when requesting the Access Token Response | ||
*/ | ||
public final void setRestOperations(RestOperations restOperations) { |
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 document what the RestOperations required (i.e. the types of converters it would need, error handling, etc)
* | ||
* @param restOperations the {@link RestOperations} used when requesting the Access Token Response | ||
*/ | ||
public final void setRestOperations(RestOperations restOperations) { |
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.
Same comments as the other setRestOperations
import org.springframework.http.ResponseEntity; | ||
import org.springframework.http.client.ClientHttpResponse; | ||
import org.springframework.http.converter.FormHttpMessageConverter; | ||
import org.springframework.security.oauth2.client.endpoint.converter.OAuth2AuthorizationCodeGrantRequestEntityConverter; |
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'm wondering if to fix the tangle if we could move OAuth2AuthorizationCodeGrantRequestEntityConverter
and OAuth2ClientCredentialsGrantRequestEntityConverter
to org.springframework.security.oauth2.core.http.converter
d54e598
to
34f7f5d
Compare
import org.springframework.http.converter.FormHttpMessageConverter; | ||
import org.springframework.http.converter.HttpMessageConverter; | ||
import org.springframework.security.oauth2.client.http.OAuth2ErrorResponseErrorHandler; | ||
import org.springframework.security.oauth2.client.http.converter.OAuth2AuthorizationCodeGrantRequestEntityConverter; |
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.
Unfortunately this is another package tangle. The client.endpoint
package refers to http.converter
above and http.converter
refers to client.endpoint
@rwinch
|
Thanks for the change. Overall it looks good. Before we merge:
Once that is done and the build passes, please feel free to merge. |
Thanks @rwinch. This is now in master. |
This PR resolves #5547 and #5466
The 1st commit pushes most of the code from
DefaultClientCredentialsTokenResponseClient
to an abstract implementationAbstractOAuth2AccessTokenResponseClient
to allow for reuse in the next commit.The 2nd commit adds a new implementation of
OAuth2AccessTokenResponseClient
for theauthorization_code
grantDefaultAuthorizationCodeTokenResponseClient
- extendingAbstractOAuth2AccessTokenResponseClient
.The 3rd commit makes
DefaultAuthorizationCodeTokenResponseClient
the default client replacing the previous defaultNimbusAuthorizationCodeTokenResponseClient
.