21
21
import com .google .common .collect .ImmutableSet ;
22
22
import com .google .gson .JsonElement ;
23
23
import io .cdap .plugin .http .common .BaseHttpConfig ;
24
- import io .cdap .plugin .http .common .OAuth2ClientAuthentication ;
25
24
import io .cdap .plugin .http .common .OAuth2GrantType ;
26
25
import io .cdap .plugin .http .common .pagination .page .JSONUtil ;
27
26
import io .cdap .plugin .http .source .common .BaseHttpSourceConfig ;
31
30
import org .apache .http .client .utils .URIBuilder ;
32
31
import org .apache .http .impl .client .CloseableHttpClient ;
33
32
import org .apache .http .impl .client .HttpClients ;
33
+ import org .apache .http .message .BasicHeader ;
34
34
import org .apache .http .message .BasicNameValuePair ;
35
35
import org .apache .http .util .EntityUtils ;
36
36
44
44
import java .time .Duration ;
45
45
import java .time .Instant ;
46
46
import java .util .ArrayList ;
47
+ import java .util .Base64 ;
47
48
import java .util .Date ;
48
49
import java .util .List ;
49
- import java .util .Objects ;
50
50
import javax .annotation .Nullable ;
51
51
52
52
/**
53
53
* A class which contains utilities to make OAuth2 specific calls.
54
54
*/
55
55
public class OAuthUtil {
56
56
57
+ private static final String PARAM_GRANT_TYPE = "grant_type" ;
58
+ private static final String PARAM_CLIENT_ID = "client_id" ;
59
+ private static final String PARAM_CLIENT_SECRET = "client_secret" ;
60
+ private static final String PARAM_REFRESH_TOKEN = "refresh_token" ;
61
+ private static final String PARAM_SCOPE = "scope" ;
62
+
57
63
/**
58
64
* Get Authorization header based on the config parameters provided
59
65
*
@@ -116,8 +122,8 @@ public static AccessToken getAccessToken(CloseableHttpClient httpclient, BaseHtt
116
122
* Retrieves an OAuth2 access token using the Client Credentials grant type.
117
123
*
118
124
* <p>This method constructs an HTTP POST request to fetch an access token from the authorization
119
- * server. The client authentication method (either "BODY" or "REQUEST") determines whether client
120
- * credentials are sent in the request body or as query parameters in the URL .</p>
125
+ * server. The client authentication method (either "BODY" or "REQUEST" or "BASIC_AUTH_HEADER" ) determines whether
126
+ * client credentials are sent in the request body or as query parameters or as basic auth header .</p>
121
127
*
122
128
* <p>Steps:
123
129
* 1. If client authentication is set to "BODY": - Constructs a URI using the token URL. - Adds
@@ -127,7 +133,11 @@ public static AccessToken getAccessToken(CloseableHttpClient httpclient, BaseHtt
127
133
* 2. If client authentication is set to "REQUEST": - Constructs a URI with client credentials as
128
134
* query parameters. - Creates an HTTP POST request with the URI.
129
135
* <br>
130
- * 3. Calls `fetchAccessToken(httpclient,httppost)` to execute the request and retrieve the
136
+ * 3. If client authentication is set to "BASIC_AUTH_HEADER": - Constructs a URI with client credentials first
137
+ * concatenated and encoded to Base64 and passed a Basic Authorization Header and
138
+ * grant type and scope as part of body.
139
+ * <br>
140
+ * 4. Calls `fetchAccessToken(httpclient,httppost)` to execute the request and retrieve the
131
141
* token.
132
142
*
133
143
* @param httpclient The HTTP client to execute the request.
@@ -139,29 +149,51 @@ public static AccessToken getAccessTokenByClientCredentials(CloseableHttpClient
139
149
BaseHttpConfig config ) throws IOException {
140
150
URI uri ;
141
151
HttpPost httppost ;
152
+
142
153
try {
143
- if (Objects .equals (config .getOauth2ClientAuthentication ().getValue (),
144
- OAuth2ClientAuthentication .BODY .getValue ())) {
145
- uri = new URIBuilder (config .getTokenUrl ()).build ();
146
- List <BasicNameValuePair > nameValuePairs = new ArrayList <>();
147
- nameValuePairs .add (
148
- new BasicNameValuePair ("grant_type" , OAuth2GrantType .CLIENT_CREDENTIALS .getValue ()));
149
- nameValuePairs .add (new BasicNameValuePair ("client_id" , config .getClientId ()));
150
- nameValuePairs .add (new BasicNameValuePair ("client_secret" , config .getClientSecret ()));
151
- if (!Strings .isNullOrEmpty (config .getScopes ())) {
152
- nameValuePairs .add (new BasicNameValuePair ("scope" , config .getScopes ()));
153
- }
154
- httppost = new HttpPost (uri );
155
- httppost .setEntity (new UrlEncodedFormEntity (nameValuePairs ));
156
- } else {
157
- URIBuilder uriBuilder = new URIBuilder (config .getTokenUrl ()).setParameter ("client_id" ,
158
- config .getClientId ()).setParameter ("client_secret" , config .getClientSecret ())
159
- .setParameter ("grant_type" , OAuth2GrantType .CLIENT_CREDENTIALS .getValue ());
160
- if (!Strings .isNullOrEmpty (config .getScopes ())) {
161
- uriBuilder .setParameter ("scope" , config .getScopes ());
162
- }
163
- uri = uriBuilder .build ();
164
- httppost = new HttpPost (uri );
154
+ List <BasicNameValuePair > nameValuePairs = new ArrayList <>();
155
+ switch (config .getOauth2ClientAuthentication ()) {
156
+ case BODY :
157
+ uri = new URIBuilder (config .getTokenUrl ()).build ();
158
+ nameValuePairs .add (
159
+ new BasicNameValuePair (PARAM_GRANT_TYPE , OAuth2GrantType .CLIENT_CREDENTIALS .getValue ()));
160
+ nameValuePairs .add (new BasicNameValuePair (PARAM_CLIENT_ID , config .getClientId ()));
161
+ nameValuePairs .add (new BasicNameValuePair (PARAM_CLIENT_SECRET , config .getClientSecret ()));
162
+ if (!Strings .isNullOrEmpty (config .getScopes ())) {
163
+ nameValuePairs .add (new BasicNameValuePair (PARAM_SCOPE , config .getScopes ()));
164
+ }
165
+ httppost = new HttpPost (uri );
166
+ httppost .setEntity (new UrlEncodedFormEntity (nameValuePairs ));
167
+ break ;
168
+
169
+ case REQUEST_PARAMETER :
170
+ URIBuilder uriBuilder = new URIBuilder (config .getTokenUrl ()).setParameter (PARAM_CLIENT_ID ,
171
+ config .getClientId ())
172
+ .setParameter (PARAM_CLIENT_SECRET , config .getClientSecret ())
173
+ .setParameter (PARAM_GRANT_TYPE , OAuth2GrantType .CLIENT_CREDENTIALS .getValue ());
174
+ if (!Strings .isNullOrEmpty (config .getScopes ())) {
175
+ uriBuilder .setParameter (PARAM_SCOPE , config .getScopes ());
176
+ }
177
+ uri = uriBuilder .build ();
178
+ httppost = new HttpPost (uri );
179
+ break ;
180
+
181
+ case BASIC_AUTH_HEADER :
182
+ String credentials = config .getClientId () + ":" + config .getClientSecret ();
183
+ String basicAuthHeader = String .format ("Basic %s" , Base64 .getEncoder ()
184
+ .encodeToString (credentials .getBytes (StandardCharsets .UTF_8 )));
185
+ nameValuePairs .add (new BasicNameValuePair (PARAM_SCOPE , config .getScopes ()));
186
+ nameValuePairs .add (new BasicNameValuePair (PARAM_GRANT_TYPE , OAuth2GrantType .CLIENT_CREDENTIALS .getValue ()));
187
+ uri = new URIBuilder (config .getTokenUrl ()).build ();
188
+ httppost = new HttpPost (uri );
189
+ httppost .setHeader (new BasicHeader ("Authorization" , basicAuthHeader ));
190
+ httppost .setEntity (new UrlEncodedFormEntity (nameValuePairs ));
191
+ break ;
192
+
193
+ default :
194
+ throw new IllegalArgumentException (
195
+ String .format ("Unknown OAuth client authentication '%s'" ,
196
+ config .getOauth2ClientAuthentication ().getValue ()));
165
197
}
166
198
return fetchAccessToken (httpclient , httppost );
167
199
} catch (URISyntaxException e ) {
@@ -205,10 +237,10 @@ public static AccessToken getAccessTokenByRefreshToken(CloseableHttpClient httpc
205
237
URI uri ;
206
238
try {
207
239
uri = new URIBuilder (config .getTokenUrl ())
208
- .setParameter ("client_id" , config .getClientId ())
209
- .setParameter ("client_secret" , config .getClientSecret ())
210
- .setParameter ("refresh_token" , config .getRefreshToken ())
211
- .setParameter ("grant_type" , "refresh_token" )
240
+ .setParameter (PARAM_CLIENT_ID , config .getClientId ())
241
+ .setParameter (PARAM_CLIENT_SECRET , config .getClientSecret ())
242
+ .setParameter (PARAM_REFRESH_TOKEN , config .getRefreshToken ())
243
+ .setParameter (PARAM_GRANT_TYPE , OAuth2GrantType . REFRESH_TOKEN . getValue () )
212
244
.build ();
213
245
HttpPost httppost = new HttpPost (uri );
214
246
return fetchAccessToken (httpclient , httppost );
@@ -232,7 +264,16 @@ private static AccessToken fetchAccessToken(CloseableHttpClient httpclient, Http
232
264
233
265
JsonElement accessTokenElement = JSONUtil .toJsonObject (responseString ).get ("access_token" );
234
266
if (accessTokenElement == null ) {
235
- throw new IllegalArgumentException ("Access token not found" );
267
+ String errorResponse ;
268
+ if (response .getStatusLine () != null ) {
269
+ errorResponse = String .format ("Response Code: '%s', Error Message:'%s'." ,
270
+ response .getStatusLine ().getStatusCode (),
271
+ response .getStatusLine ().getReasonPhrase ());
272
+ } else {
273
+ errorResponse = response .toString ();
274
+ }
275
+ throw new IllegalArgumentException (
276
+ "Access token not found with Details: " + errorResponse );
236
277
}
237
278
238
279
JsonElement expiresInElement = JSONUtil .toJsonObject (responseString ).get ("expires_in" );
0 commit comments