1616
1717package  org .springframework .security .oauth2 .client .endpoint ;
1818
19- import  java .util .Collections ;
20- import  java .util .Set ;
21- 
2219import  reactor .core .publisher .Mono ;
2320
2421import  org .springframework .core .convert .converter .Converter ;
3027import  org .springframework .security .oauth2 .core .endpoint .OAuth2ParameterNames ;
3128import  org .springframework .security .oauth2 .core .web .reactive .function .OAuth2BodyExtractors ;
3229import  org .springframework .util .Assert ;
33- import  org .springframework .util .CollectionUtils ;
3430import  org .springframework .util .LinkedMultiValueMap ;
3531import  org .springframework .util .MultiValueMap ;
36- import  org .springframework .util .StringUtils ;
3732import  org .springframework .web .reactive .function .BodyExtractor ;
3833import  org .springframework .web .reactive .function .BodyInserters ;
39- import  org .springframework .web .reactive .function .client .ClientResponse ;
4034import  org .springframework .web .reactive .function .client .WebClient ;
4135import  org .springframework .web .reactive .function .client .WebClient .RequestHeadersSpec ;
4236
5448 * 
5549 * @param <T> type of grant request 
5650 * @author Phil Clay 
51+  * @author Steve Riesenberg 
5752 * @since 5.3 
5853 * @see <a href="https://tools.ietf.org/html/rfc6749#section-3.2">RFC-6749 Token 
5954 * Endpoint</a> 
@@ -72,7 +67,7 @@ public abstract class AbstractWebClientReactiveOAuth2AccessTokenResponseClient<T
7267
7368	private  Converter <T , HttpHeaders > headersConverter  = new  DefaultOAuth2TokenRequestHeadersConverter <>();
7469
75- 	private  Converter <T , MultiValueMap <String , String >> parametersConverter  = this ::populateTokenRequestParameters ;
70+ 	private  Converter <T , MultiValueMap <String , String >> parametersConverter  = this ::createParameters ;
7671
7772	private  BodyExtractor <Mono <OAuth2AccessTokenResponse >, ReactiveHttpInputMessage > bodyExtractor  = OAuth2BodyExtractors 
7873		.oauth2AccessTokenResponse ();
@@ -86,18 +81,11 @@ public Mono<OAuth2AccessTokenResponse> getTokenResponse(T grantRequest) {
8681		// @formatter:off 
8782		return  Mono .defer (() -> this .requestEntityConverter .convert (grantRequest )
8883				.exchange ()
89- 				.flatMap ((response ) -> readTokenResponse ( grantRequest ,  response ))
84+ 				.flatMap ((response ) -> response . body ( this . bodyExtractor ))
9085		);
9186		// @formatter:on 
9287	}
9388
94- 	/** 
95- 	 * Returns the {@link ClientRegistration} for the given {@code grantRequest}. 
96- 	 * @param grantRequest the grant request 
97- 	 * @return the {@link ClientRegistration} for the given {@code grantRequest}. 
98- 	 */ 
99- 	abstract  ClientRegistration  clientRegistration (T  grantRequest );
100- 
10189	private  RequestHeadersSpec <?> validatingPopulateRequest (T  grantRequest ) {
10290		validateClientAuthenticationMethod (grantRequest );
10391		return  populateRequest (grantRequest );
@@ -117,128 +105,37 @@ private void validateClientAuthenticationMethod(T grantRequest) {
117105	}
118106
119107	private  RequestHeadersSpec <?> populateRequest (T  grantRequest ) {
108+ 		MultiValueMap <String , String > parameters  = this .parametersConverter .convert (grantRequest );
120109		return  this .webClient .post ()
121- 			.uri (clientRegistration ( grantRequest ).getProviderDetails ().getTokenUri ())
110+ 			.uri (grantRequest . getClientRegistration ( ).getProviderDetails ().getTokenUri ())
122111			.headers ((headers ) -> {
123- 				HttpHeaders  headersToAdd  = getHeadersConverter () .convert (grantRequest );
112+ 				HttpHeaders  headersToAdd  = this . headersConverter .convert (grantRequest );
124113				if  (headersToAdd  != null ) {
125114					headers .addAll (headersToAdd );
126115				}
127116			})
128- 			.body (createTokenRequestBody ( grantRequest ));
117+ 			.body (BodyInserters . fromFormData ( parameters ));
129118	}
130119
131120	/** 
132- 	 * Populates default parameters for the token request. 
133- 	 * @param grantRequest the grant request 
134- 	 * @return the parameters populated for the token request. 
121+ 	 * Returns a {@link MultiValueMap} of the parameters used in the OAuth 2.0 Access 
122+ 	 * Token Request body. 
123+ 	 * @param grantRequest the authorization grant request 
124+ 	 * @return a {@link MultiValueMap} of the parameters used in the OAuth 2.0 Access 
125+ 	 * Token Request body 
135126	 */ 
136- 	private  MultiValueMap <String , String > populateTokenRequestParameters (T  grantRequest ) {
127+ 	MultiValueMap <String , String > createParameters (T  grantRequest ) {
128+ 		ClientRegistration  clientRegistration  = grantRequest .getClientRegistration ();
137129		MultiValueMap <String , String > parameters  = new  LinkedMultiValueMap <>();
138- 		parameters .add (OAuth2ParameterNames .GRANT_TYPE , grantRequest .getGrantType ().getValue ());
139- 		return  parameters ;
140- 	}
141- 
142- 	/** 
143- 	 * Combine the results of {@code parametersConverter} and 
144- 	 * {@link #populateTokenRequestBody}. 
145- 	 * 
146- 	 * <p> 
147- 	 * This method pre-populates the body with some standard properties, and then 
148- 	 * delegates to 
149- 	 * {@link #populateTokenRequestBody(AbstractOAuth2AuthorizationGrantRequest, BodyInserters.FormInserter)} 
150- 	 * for subclasses to further populate the body before returning. 
151- 	 * </p> 
152- 	 * @param grantRequest the grant request 
153- 	 * @return the body for the token request. 
154- 	 */ 
155- 	private  BodyInserters .FormInserter <String > createTokenRequestBody (T  grantRequest ) {
156- 		MultiValueMap <String , String > parameters  = getParametersConverter ().convert (grantRequest );
157- 		return  populateTokenRequestBody (grantRequest , BodyInserters .fromFormData (parameters ));
158- 	}
159- 
160- 	/** 
161- 	 * Populates the body of the token request. 
162- 	 * 
163- 	 * <p> 
164- 	 * By default, populates properties that are common to all grant types. Subclasses can 
165- 	 * extend this method to populate grant type specific properties. 
166- 	 * </p> 
167- 	 * @param grantRequest the grant request 
168- 	 * @param body the body to populate 
169- 	 * @return the populated body 
170- 	 */ 
171- 	BodyInserters .FormInserter <String > populateTokenRequestBody (T  grantRequest ,
172- 			BodyInserters .FormInserter <String > body ) {
173- 		ClientRegistration  clientRegistration  = clientRegistration (grantRequest );
130+ 		parameters .set (OAuth2ParameterNames .GRANT_TYPE , grantRequest .getGrantType ().getValue ());
174131		if  (!ClientAuthenticationMethod .CLIENT_SECRET_BASIC 
175132			.equals (clientRegistration .getClientAuthenticationMethod ())) {
176- 			body . with (OAuth2ParameterNames .CLIENT_ID , clientRegistration .getClientId ());
133+ 			parameters . set (OAuth2ParameterNames .CLIENT_ID , clientRegistration .getClientId ());
177134		}
178135		if  (ClientAuthenticationMethod .CLIENT_SECRET_POST .equals (clientRegistration .getClientAuthenticationMethod ())) {
179- 			body .with (OAuth2ParameterNames .CLIENT_SECRET , clientRegistration .getClientSecret ());
180- 		}
181- 		Set <String > scopes  = scopes (grantRequest );
182- 		if  (!CollectionUtils .isEmpty (scopes )) {
183- 			body .with (OAuth2ParameterNames .SCOPE , StringUtils .collectionToDelimitedString (scopes , " " ));
184- 		}
185- 		return  body ;
186- 	}
187- 
188- 	/** 
189- 	 * Returns the scopes to include as a property in the token request. 
190- 	 * @param grantRequest the grant request 
191- 	 * @return the scopes to include as a property in the token request. 
192- 	 */ 
193- 	abstract  Set <String > scopes (T  grantRequest );
194- 
195- 	/** 
196- 	 * Returns the scopes to include in the response if the authorization server returned 
197- 	 * no scopes in the response. 
198- 	 * 
199- 	 * <p> 
200- 	 * As per <a href="https://tools.ietf.org/html/rfc6749#section-5.1">RFC-6749 Section 
201- 	 * 5.1 Successful Access Token Response</a>, if AccessTokenResponse.scope is empty, 
202- 	 * then default to the scope originally requested by the client in the Token Request. 
203- 	 * </p> 
204- 	 * @param grantRequest the grant request 
205- 	 * @return the scopes to include in the response if the authorization server returned 
206- 	 * no scopes. 
207- 	 */ 
208- 	Set <String > defaultScopes (T  grantRequest ) {
209- 		return  Collections .emptySet ();
210- 	}
211- 
212- 	/** 
213- 	 * Reads the token response from the response body. 
214- 	 * @param grantRequest the request for which the response was received. 
215- 	 * @param response the client response from which to read 
216- 	 * @return the token response from the response body. 
217- 	 */ 
218- 	private  Mono <OAuth2AccessTokenResponse > readTokenResponse (T  grantRequest , ClientResponse  response ) {
219- 		return  response .body (this .bodyExtractor )
220- 			.map ((tokenResponse ) -> populateTokenResponse (grantRequest , tokenResponse ));
221- 	}
222- 
223- 	/** 
224- 	 * Populates the given {@link OAuth2AccessTokenResponse} with additional details from 
225- 	 * the grant request. 
226- 	 * @param grantRequest the request for which the response was received. 
227- 	 * @param tokenResponse the original token response 
228- 	 * @return a token response optionally populated with additional details from the 
229- 	 * request. 
230- 	 */ 
231- 	OAuth2AccessTokenResponse  populateTokenResponse (T  grantRequest , OAuth2AccessTokenResponse  tokenResponse ) {
232- 		if  (CollectionUtils .isEmpty (tokenResponse .getAccessToken ().getScopes ())) {
233- 			Set <String > defaultScopes  = defaultScopes (grantRequest );
234- 			// @formatter:off 
235- 			tokenResponse  = OAuth2AccessTokenResponse 
236- 					.withResponse (tokenResponse )
237- 					.scopes (defaultScopes )
238- 					.build ();
239- 			// @formatter:on 
136+ 			parameters .set (OAuth2ParameterNames .CLIENT_SECRET , clientRegistration .getClientSecret ());
240137		}
241- 		return  tokenResponse ;
138+ 		return  parameters ;
242139	}
243140
244141	/** 
@@ -247,22 +144,11 @@ OAuth2AccessTokenResponse populateTokenResponse(T grantRequest, OAuth2AccessToke
247144	 * @param webClient the {@link WebClient} used when requesting the Access Token 
248145	 * Response 
249146	 */ 
250- 	public  void  setWebClient (WebClient  webClient ) {
147+ 	public  final   void  setWebClient (WebClient  webClient ) {
251148		Assert .notNull (webClient , "webClient cannot be null" );
252149		this .webClient  = webClient ;
253150	}
254151
255- 	/** 
256- 	 * Returns the {@link Converter} used for converting the 
257- 	 * {@link AbstractOAuth2AuthorizationGrantRequest} instance to a {@link HttpHeaders} 
258- 	 * used in the OAuth 2.0 Access Token Request headers. 
259- 	 * @return the {@link Converter} used for converting the 
260- 	 * {@link AbstractOAuth2AuthorizationGrantRequest} to {@link HttpHeaders} 
261- 	 */ 
262- 	final  Converter <T , HttpHeaders > getHeadersConverter () {
263- 		return  this .headersConverter ;
264- 	}
265- 
266152	/** 
267153	 * Sets the {@link Converter} used for converting the 
268154	 * {@link AbstractOAuth2AuthorizationGrantRequest} instance to a {@link HttpHeaders} 
@@ -305,17 +191,6 @@ public final void addHeadersConverter(Converter<T, HttpHeaders> headersConverter
305191		this .requestEntityConverter  = this ::populateRequest ;
306192	}
307193
308- 	/** 
309- 	 * Returns the {@link Converter} used for converting the 
310- 	 * {@link AbstractOAuth2AuthorizationGrantRequest} instance to a {@link MultiValueMap} 
311- 	 * used in the OAuth 2.0 Access Token Request body. 
312- 	 * @return the {@link Converter} used for converting the 
313- 	 * {@link AbstractOAuth2AuthorizationGrantRequest} to {@link MultiValueMap} 
314- 	 */ 
315- 	final  Converter <T , MultiValueMap <String , String >> getParametersConverter () {
316- 		return  this .parametersConverter ;
317- 	}
318- 
319194	/** 
320195	 * Sets the {@link Converter} used for converting the 
321196	 * {@link AbstractOAuth2AuthorizationGrantRequest} instance to a {@link MultiValueMap} 
0 commit comments