Skip to content

Commit b73346e

Browse files
Amit-CloudSufipsainics
authored andcommitted
Added GrantType and Client Authentication for the HttpOauth2
1 parent 4a31768 commit b73346e

File tree

12 files changed

+742
-66
lines changed

12 files changed

+742
-66
lines changed

Diff for: src/main/java/io/cdap/plugin/http/common/BaseHttpConfig.java

+82-16
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@
2929

3030
import java.io.File;
3131
import java.util.Optional;
32+
import java.util.stream.Stream;
3233
import javax.annotation.Nullable;
3334

34-
3535
/**
3636
* Base configuration for HTTP Source and HTTP Sink
3737
*/
@@ -48,6 +48,8 @@ public abstract class BaseHttpConfig extends ReferencePluginConfig {
4848
public static final String PROPERTY_PROXY_URL = "proxyUrl";
4949
public static final String PROPERTY_PROXY_USERNAME = "proxyUsername";
5050
public static final String PROPERTY_PROXY_PASSWORD = "proxyPassword";
51+
public static final String PROPERTY_OAUTH2_GRANT_TYPE = "oauth2GrantType";
52+
public static final String PROPERTY_OAUTH2_CLIENT_AUTHENTICATION = "oauth2ClientAuthentication";
5153

5254
public static final String PROPERTY_AUTH_TYPE_LABEL = "Auth type";
5355

@@ -93,6 +95,18 @@ public abstract class BaseHttpConfig extends ReferencePluginConfig {
9395
@Macro
9496
protected String authUrl;
9597

98+
@Nullable
99+
@Name(PROPERTY_OAUTH2_GRANT_TYPE)
100+
@Description("Which Oauth2 grant type flow is used.")
101+
@Macro
102+
protected String oauth2GrantType;
103+
104+
@Nullable
105+
@Name(PROPERTY_OAUTH2_CLIENT_AUTHENTICATION)
106+
@Description("Send auth credentials in the request body or as query param.")
107+
@Macro
108+
protected String oauth2ClientAuthentication;
109+
96110
@Nullable
97111
@Name(PROPERTY_TOKEN_URL)
98112
@Description("Endpoint for the resource server, which exchanges the authorization code for an access token.")
@@ -208,6 +222,19 @@ public String getOAuth2Enabled() {
208222
return oauth2Enabled;
209223
}
210224

225+
public OAuth2GrantType getOauth2GrantType() {
226+
OAuth2GrantType grantType = OAuth2GrantType.getGrantType(oauth2GrantType);
227+
return getEnumValueByString(OAuth2GrantType.class, grantType.getValue(),
228+
PROPERTY_OAUTH2_GRANT_TYPE);
229+
}
230+
231+
public OAuth2ClientAuthentication getOauth2ClientAuthentication() {
232+
OAuth2ClientAuthentication clientAuthentication = OAuth2ClientAuthentication.getClientAuthentication(
233+
oauth2ClientAuthentication);
234+
return getEnumValueByString(OAuth2ClientAuthentication.class,
235+
clientAuthentication.getValue(), PROPERTY_OAUTH2_CLIENT_AUTHENTICATION);
236+
}
237+
211238
@Nullable
212239
public String getAuthUrl() {
213240
return authUrl;
@@ -365,21 +392,7 @@ public void validate(FailureCollector failureCollector) {
365392
AuthType authType = getAuthType();
366393
switch (authType) {
367394
case OAUTH2:
368-
String reasonOauth2 = "OAuth2 is enabled";
369-
if (!containsMacro(PROPERTY_TOKEN_URL)) {
370-
assertIsSetWithFailureCollector(getTokenUrl(), PROPERTY_TOKEN_URL, reasonOauth2, failureCollector);
371-
}
372-
if (!containsMacro(PROPERTY_CLIENT_ID)) {
373-
assertIsSetWithFailureCollector(getClientId(), PROPERTY_CLIENT_ID, reasonOauth2, failureCollector);
374-
}
375-
if (!containsMacro((PROPERTY_CLIENT_SECRET))) {
376-
assertIsSetWithFailureCollector(getClientSecret(), PROPERTY_CLIENT_SECRET, reasonOauth2,
377-
failureCollector);
378-
}
379-
if (!containsMacro(PROPERTY_REFRESH_TOKEN)) {
380-
assertIsSetWithFailureCollector(getRefreshToken(), PROPERTY_REFRESH_TOKEN, reasonOauth2,
381-
failureCollector);
382-
}
395+
validateOAuth2Fields(failureCollector);
383396
break;
384397
case SERVICE_ACCOUNT:
385398
String reasonSA = "Service Account is enabled";
@@ -423,4 +436,57 @@ public static void assertIsSetWithFailureCollector(Object propertyValue, String
423436
null).withConfigProperty(propertyName);
424437
}
425438
}
439+
440+
private void validateOAuth2Fields(FailureCollector failureCollector) {
441+
String reasonOauth2GrantType = String.format("OAuth2 is enabled and grant type is %s.",
442+
getOauth2GrantType().getValue());
443+
if (!containsMacro(PROPERTY_TOKEN_URL)) {
444+
assertIsSetWithFailureCollector(getTokenUrl(), PROPERTY_TOKEN_URL,
445+
reasonOauth2GrantType, failureCollector);
446+
}
447+
if (!containsMacro(PROPERTY_CLIENT_ID)) {
448+
assertIsSetWithFailureCollector(getClientId(), PROPERTY_CLIENT_ID,
449+
reasonOauth2GrantType, failureCollector);
450+
}
451+
if (!containsMacro(PROPERTY_CLIENT_SECRET)) {
452+
assertIsSetWithFailureCollector(getClientSecret(), PROPERTY_CLIENT_SECRET,
453+
reasonOauth2GrantType, failureCollector);
454+
}
455+
if (!containsMacro(PROPERTY_OAUTH2_CLIENT_AUTHENTICATION)) {
456+
assertIsSetWithFailureCollector(getOauth2ClientAuthentication(),
457+
PROPERTY_OAUTH2_CLIENT_AUTHENTICATION, reasonOauth2GrantType, failureCollector);
458+
}
459+
// in case of refresh token grant type, also check additional fields
460+
if (OAuth2GrantType.REFRESH_TOKEN.equals(getOauth2GrantType())) {
461+
if (!containsMacro(PROPERTY_REFRESH_TOKEN)) {
462+
assertIsSetWithFailureCollector(getRefreshToken(), PROPERTY_REFRESH_TOKEN,
463+
reasonOauth2GrantType, failureCollector);
464+
}
465+
}
466+
failureCollector.getOrThrowException();
467+
}
468+
469+
/**
470+
* Retrieves the corresponding enum constant of a given string value.
471+
*
472+
* <p>This method takes an enum class that implements {@code EnumWithValue} and searches for an
473+
* enum constant that matches the provided string value. If no matching value is found, it throws
474+
* an {@code InvalidConfigPropertyException}.</p>
475+
*
476+
* @param <T> the type of enum that implements {@code EnumWithValue}
477+
* @param enumClass the class of the enum to search within
478+
* @param stringValue the string representation of the enum value
479+
* @param propertyName the name of the property (used for error messages)
480+
* @return the corresponding enum constant if a match is found
481+
* @throws InvalidConfigPropertyException if the string value does not match any enum constant
482+
*/
483+
public static <T extends EnumWithValue> T
484+
getEnumValueByString(Class<T> enumClass, String stringValue, String propertyName) {
485+
return Stream.of(enumClass.getEnumConstants())
486+
.filter(keyType -> keyType.getValue().equalsIgnoreCase(stringValue))
487+
.findAny()
488+
.orElseThrow(() -> new InvalidConfigPropertyException(
489+
String.format("Unsupported value for '%s': '%s'", propertyName, stringValue),
490+
propertyName));
491+
}
426492
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright © 2025 Cask Data, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
17+
package io.cdap.plugin.http.common;
18+
19+
import java.util.Objects;
20+
21+
/**
22+
* Enum encoding the handled Oauth2 Client Authentication
23+
*/
24+
public enum OAuth2ClientAuthentication implements EnumWithValue {
25+
BODY("body", "Body"),
26+
REQUEST_PARAMETER("request_parameter", "Request Parameter");
27+
28+
private final String value;
29+
private final String label;
30+
31+
OAuth2ClientAuthentication(String value, String label) {
32+
this.value = value;
33+
this.label = label;
34+
}
35+
36+
/**
37+
* Determines the OAuth2 client authentication method based on the provided input.
38+
*
39+
* <p>This method checks if the given client authentication type matches the predefined
40+
* BODY authentication type. If it matches, the method returns the BODY authentication. Otherwise,
41+
* it defaults to REQUEST_PARAMETER authentication.</p>
42+
*
43+
* @param clientAuthentication The client authentication type as a {@link String}. It can be
44+
* either the value or the label of the BODY authentication method.
45+
* @return {@link OAuth2ClientAuthentication} The corresponding authentication type. Returns
46+
* {@code BODY} if the input matches its value or label; otherwise, returns
47+
* {@code REQUEST_PARAMETER}.
48+
*/
49+
public static OAuth2ClientAuthentication getClientAuthentication(String clientAuthentication) {
50+
if (Objects.equals(clientAuthentication, BODY.getValue()) || Objects.equals(
51+
clientAuthentication, BODY.getLabel())) {
52+
return BODY;
53+
} else {
54+
return REQUEST_PARAMETER;
55+
}
56+
}
57+
58+
@Override
59+
public String getValue() {
60+
return value;
61+
}
62+
63+
public String getLabel() {
64+
return label;
65+
}
66+
67+
@Override
68+
public String toString() {
69+
return this.getValue();
70+
}
71+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Copyright © 2025 Cask Data, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
17+
package io.cdap.plugin.http.common;
18+
19+
import java.util.Objects;
20+
21+
/**
22+
* Enum encoding the handled Oauth2 Grant Types
23+
*/
24+
public enum OAuth2GrantType implements EnumWithValue {
25+
REFRESH_TOKEN("refresh_token", "Refresh Token"),
26+
CLIENT_CREDENTIALS("client_credentials", "Client Credentials");
27+
28+
private final String value;
29+
private final String label;
30+
31+
OAuth2GrantType(String value, String label) {
32+
this.value = value;
33+
this.label = label;
34+
}
35+
36+
/**
37+
* Determines the OAuth2 grant type based on the provided string value.
38+
*
39+
* <p>This method checks whether the given OAuth2 grant type string matches
40+
* the CLIENT_CREDENTIALS grant type based on its value or label. If it matches,
41+
* CLIENT_CREDENTIALS is returned; otherwise, REFRESH_TOKEN is returned as the default.</p>
42+
*
43+
* @param oauth2GrantType The OAuth2 grant type as a string.
44+
* @return The corresponding {@link OAuth2GrantType}, either CLIENT_CREDENTIALS or REFRESH_TOKEN.
45+
*/
46+
public static OAuth2GrantType getGrantType(String oauth2GrantType) {
47+
if (Objects.equals(oauth2GrantType, CLIENT_CREDENTIALS.getValue()) || Objects.equals(
48+
oauth2GrantType, CLIENT_CREDENTIALS.getLabel())) {
49+
return CLIENT_CREDENTIALS;
50+
} else {
51+
return REFRESH_TOKEN;
52+
}
53+
}
54+
55+
@Override
56+
public String getValue() {
57+
return value;
58+
}
59+
60+
public String getLabel() {
61+
return label;
62+
}
63+
64+
@Override
65+
public String toString() {
66+
return this.getValue();
67+
}
68+
}

Diff for: src/main/java/io/cdap/plugin/http/common/http/HttpClient.java

+9-1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.apache.http.impl.client.BasicCredentialsProvider;
3333
import org.apache.http.impl.client.CloseableHttpClient;
3434
import org.apache.http.impl.client.HttpClientBuilder;
35+
import org.apache.http.impl.client.HttpClients;
3536
import org.apache.http.message.BasicHeader;
3637

3738
import java.io.Closeable;
@@ -132,7 +133,14 @@ public CloseableHttpClient createHttpClient(String pageUriStr) throws IOExceptio
132133
httpClientBuilder.setProxy(proxyHost);
133134
}
134135
httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
135-
136+
ArrayList<Header> clientHeaders = new ArrayList<>();
137+
// If OAuth2 is enabled, fetch an access token and add it as an Authorization header.
138+
if (Boolean.TRUE.equals(config.getOauth2Enabled())) {
139+
AccessToken oauth2AccessToken = OAuthUtil.getAccessToken(httpClientBuilder.build(), config);
140+
clientHeaders.add(new BasicHeader("Authorization",
141+
String.format("Bearer %s", oauth2AccessToken.getTokenValue())));
142+
}
143+
httpClientBuilder.setDefaultHeaders(clientHeaders);
136144
return httpClientBuilder.build();
137145
}
138146

0 commit comments

Comments
 (0)