16
16
17
17
package org .springframework .security .oauth2 .client .endpoint ;
18
18
19
- import java .util .Collections ;
20
- import java .util .Set ;
21
-
22
19
import reactor .core .publisher .Mono ;
23
20
24
21
import org .springframework .core .convert .converter .Converter ;
30
27
import org .springframework .security .oauth2 .core .endpoint .OAuth2ParameterNames ;
31
28
import org .springframework .security .oauth2 .core .web .reactive .function .OAuth2BodyExtractors ;
32
29
import org .springframework .util .Assert ;
33
- import org .springframework .util .CollectionUtils ;
34
30
import org .springframework .util .LinkedMultiValueMap ;
35
31
import org .springframework .util .MultiValueMap ;
36
- import org .springframework .util .StringUtils ;
37
32
import org .springframework .web .reactive .function .BodyExtractor ;
38
33
import org .springframework .web .reactive .function .BodyInserters ;
39
- import org .springframework .web .reactive .function .client .ClientResponse ;
40
34
import org .springframework .web .reactive .function .client .WebClient ;
41
35
import org .springframework .web .reactive .function .client .WebClient .RequestHeadersSpec ;
42
36
54
48
*
55
49
* @param <T> type of grant request
56
50
* @author Phil Clay
51
+ * @author Steve Riesenberg
57
52
* @since 5.3
58
53
* @see <a href="https://tools.ietf.org/html/rfc6749#section-3.2">RFC-6749 Token
59
54
* Endpoint</a>
@@ -72,7 +67,7 @@ public abstract class AbstractWebClientReactiveOAuth2AccessTokenResponseClient<T
72
67
73
68
private Converter <T , HttpHeaders > headersConverter = new DefaultOAuth2TokenRequestHeadersConverter <>();
74
69
75
- private Converter <T , MultiValueMap <String , String >> parametersConverter = this ::populateTokenRequestParameters ;
70
+ private Converter <T , MultiValueMap <String , String >> parametersConverter = this ::createParameters ;
76
71
77
72
private BodyExtractor <Mono <OAuth2AccessTokenResponse >, ReactiveHttpInputMessage > bodyExtractor = OAuth2BodyExtractors
78
73
.oauth2AccessTokenResponse ();
@@ -86,18 +81,11 @@ public Mono<OAuth2AccessTokenResponse> getTokenResponse(T grantRequest) {
86
81
// @formatter:off
87
82
return Mono .defer (() -> this .requestEntityConverter .convert (grantRequest )
88
83
.exchange ()
89
- .flatMap ((response ) -> readTokenResponse ( grantRequest , response ))
84
+ .flatMap ((response ) -> response . body ( this . bodyExtractor ))
90
85
);
91
86
// @formatter:on
92
87
}
93
88
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
-
101
89
private RequestHeadersSpec <?> validatingPopulateRequest (T grantRequest ) {
102
90
validateClientAuthenticationMethod (grantRequest );
103
91
return populateRequest (grantRequest );
@@ -117,128 +105,37 @@ private void validateClientAuthenticationMethod(T grantRequest) {
117
105
}
118
106
119
107
private RequestHeadersSpec <?> populateRequest (T grantRequest ) {
108
+ MultiValueMap <String , String > parameters = this .parametersConverter .convert (grantRequest );
120
109
return this .webClient .post ()
121
- .uri (clientRegistration ( grantRequest ).getProviderDetails ().getTokenUri ())
110
+ .uri (grantRequest . getClientRegistration ( ).getProviderDetails ().getTokenUri ())
122
111
.headers ((headers ) -> {
123
- HttpHeaders headersToAdd = getHeadersConverter () .convert (grantRequest );
112
+ HttpHeaders headersToAdd = this . headersConverter .convert (grantRequest );
124
113
if (headersToAdd != null ) {
125
114
headers .addAll (headersToAdd );
126
115
}
127
116
})
128
- .body (createTokenRequestBody ( grantRequest ));
117
+ .body (BodyInserters . fromFormData ( parameters ));
129
118
}
130
119
131
120
/**
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
135
126
*/
136
- private MultiValueMap <String , String > populateTokenRequestParameters (T grantRequest ) {
127
+ MultiValueMap <String , String > createParameters (T grantRequest ) {
128
+ ClientRegistration clientRegistration = grantRequest .getClientRegistration ();
137
129
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 ());
174
131
if (!ClientAuthenticationMethod .CLIENT_SECRET_BASIC
175
132
.equals (clientRegistration .getClientAuthenticationMethod ())) {
176
- body . with (OAuth2ParameterNames .CLIENT_ID , clientRegistration .getClientId ());
133
+ parameters . set (OAuth2ParameterNames .CLIENT_ID , clientRegistration .getClientId ());
177
134
}
178
135
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 ());
240
137
}
241
- return tokenResponse ;
138
+ return parameters ;
242
139
}
243
140
244
141
/**
@@ -247,22 +144,11 @@ OAuth2AccessTokenResponse populateTokenResponse(T grantRequest, OAuth2AccessToke
247
144
* @param webClient the {@link WebClient} used when requesting the Access Token
248
145
* Response
249
146
*/
250
- public void setWebClient (WebClient webClient ) {
147
+ public final void setWebClient (WebClient webClient ) {
251
148
Assert .notNull (webClient , "webClient cannot be null" );
252
149
this .webClient = webClient ;
253
150
}
254
151
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
-
266
152
/**
267
153
* Sets the {@link Converter} used for converting the
268
154
* {@link AbstractOAuth2AuthorizationGrantRequest} instance to a {@link HttpHeaders}
@@ -305,17 +191,6 @@ public final void addHeadersConverter(Converter<T, HttpHeaders> headersConverter
305
191
this .requestEntityConverter = this ::populateRequest ;
306
192
}
307
193
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
-
319
194
/**
320
195
* Sets the {@link Converter} used for converting the
321
196
* {@link AbstractOAuth2AuthorizationGrantRequest} instance to a {@link MultiValueMap}
0 commit comments