Skip to content
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

adding changes for the grant type client credentials mechanism #1

Open
wants to merge 7 commits into
base: develop
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ public abstract class BaseHttpSourceConfig extends ReferencePluginConfig {

public static final String PAGINATION_INDEX_PLACEHOLDER_REGEX = "\\{pagination.index\\}";
public static final String PAGINATION_INDEX_PLACEHOLDER = "{pagination.index}";
public static final String PROPERTY_GRANT_TYPE = "grantType";

@Name(PROPERTY_URL)
@Description("Url to fetch to the first page. The url must start with a protocol (e.g. http://).")
Expand Down Expand Up @@ -442,6 +443,11 @@ public abstract class BaseHttpSourceConfig extends ReferencePluginConfig {
@Description("Output schema. Is required to be set.")
protected String schema;

@Nullable
@Name(PROPERTY_GRANT_TYPE)
@Description("Value of grant type to determine the OAuth mechanism")
protected String grantType;

protected BaseHttpSourceConfig(String referenceName) {
super(referenceName);
}
Expand Down Expand Up @@ -719,6 +725,10 @@ public Schema getSchema() {
schema, e, PROPERTY_SCHEMA);
}
}
@Nullable
public String getGrantType() {
return grantType;
}

@Nullable
public Map<String, String> getHeadersMap() {
Expand Down Expand Up @@ -798,7 +808,6 @@ public void validate(FailureCollector failureCollector) {
String.format("URL value is not valid: '%s'", getUrl()), e, PROPERTY_URL);
}
}

// Validate Linear Retry Interval
if (!containsMacro(PROPERTY_RETRY_POLICY) && getRetryPolicy() == RetryPolicy.LINEAR) {
assertIsSet(getLinearRetryInterval(), PROPERTY_LINEAR_RETRY_INTERVAL, "retry policy is linear");
Expand Down Expand Up @@ -883,20 +892,22 @@ PAGINATION_INDEX_PLACEHOLDER, getPaginationType()),
// Validate OAuth2 properties
if (!containsMacro(PROPERTY_OAUTH2_ENABLED) && this.getOauth2Enabled()) {
String reasonOauth2 = "OAuth2 is enabled";
assertIsSet(getAuthUrl(), PROPERTY_AUTH_URL, reasonOauth2);
assertIsSet(getTokenUrl(), PROPERTY_TOKEN_URL, reasonOauth2);
assertIsSet(getClientId(), PROPERTY_CLIENT_ID, reasonOauth2);
assertIsSet(getClientSecret(), PROPERTY_CLIENT_SECRET, reasonOauth2);
assertIsSet(getRefreshToken(), PROPERTY_REFRESH_TOKEN, reasonOauth2);
assertIsSet(getGrantType(), PROPERTY_GRANT_TYPE, reasonOauth2);

// refresh token validate
if (refreshTokenGrantType()) {
assertIsSet(getAuthUrl(), PROPERTY_AUTH_URL, reasonOauth2);
assertIsSet(getRefreshToken(), PROPERTY_REFRESH_TOKEN, reasonOauth2);
}
}
// Validate Authentication properties
AuthType authType = getAuthType();
switch (authType) {
case OAUTH2:
String reasonOauth2 = "OAuth2 is enabled";
if (!containsMacro(PROPERTY_AUTH_URL)) {
assertIsSet(getAuthUrl(), PROPERTY_AUTH_URL, reasonOauth2);
}
if (!containsMacro(PROPERTY_TOKEN_URL)) {
assertIsSet(getTokenUrl(), PROPERTY_TOKEN_URL, reasonOauth2);
}
Expand All @@ -906,8 +917,16 @@ PAGINATION_INDEX_PLACEHOLDER, getPaginationType()),
if (!containsMacro((PROPERTY_CLIENT_SECRET))) {
assertIsSet(getClientSecret(), PROPERTY_CLIENT_SECRET, reasonOauth2);
}
if (!containsMacro(PROPERTY_REFRESH_TOKEN)) {
assertIsSet(getRefreshToken(), PROPERTY_REFRESH_TOKEN, reasonOauth2);
if (!containsMacro(PROPERTY_GRANT_TYPE)) {
assertIsSet(getGrantType(), PROPERTY_GRANT_TYPE, reasonOauth2);
if (refreshTokenGrantType()) {
if (!containsMacro(PROPERTY_REFRESH_TOKEN)) {
assertIsSet(getRefreshToken(), PROPERTY_REFRESH_TOKEN, reasonOauth2);
}
if (!containsMacro(PROPERTY_AUTH_URL)) {
assertIsSet(getAuthUrl(), PROPERTY_AUTH_URL, reasonOauth2);
}
}
}
break;
case SERVICE_ACCOUNT:
Expand Down Expand Up @@ -941,6 +960,13 @@ PAGINATION_INDEX_PLACEHOLDER, getPaginationType()),
}
}

private boolean refreshTokenGrantType() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we need this method, I can directly check for the condition where ever we are using this. In case we will add multiple grant types in future, it will create issues

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

checking the condition directly now.

if (getGrantType() == "refresh_token") {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

create an enum for grant types and change the above code also accordingly. and write grant type specific if conditions. e.g.(if grant == enum.refreshtoken) else if grant=client_credentials

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enum for grant type created and made changes to the conditions accordingly.

return true;
}
return false;
}

private boolean validateServiceAccount(FailureCollector collector) {
if (containsMacro(PROPERTY_NAME_SERVICE_ACCOUNT_FILE_PATH) || containsMacro(PROPERTY_NAME_SERVICE_ACCOUNT_JSON)) {
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,15 @@ private CloseableHttpClient createHttpClient() throws IOException {

switch (authType) {
case OAUTH2:
String accessToken = OAuthUtil.getAccessTokenByRefreshToken(HttpClients.createDefault(), config.getTokenUrl(),
config.getClientId(), config.getClientSecret(),
config.getRefreshToken());
String accessToken;
if (config.getGrantType() == "refresh_token") {
accessToken = OAuthUtil.getAccessTokenByRefreshToken(HttpClients.createDefault(), config.getTokenUrl(),
config.getClientId(), config.getClientSecret(),
config.getRefreshToken(), config.getGrantType());
} else {
accessToken = OAuthUtil.getAccessTokenByClientCredentials(HttpClients.createDefault(), config.getTokenUrl(),
config.getClientId(), config.getClientSecret(), config.getGrantType());
}
clientHeaders.add(new BasicHeader("Authorization", "Bearer " + accessToken));
break;
case SERVICE_ACCOUNT:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils;

import java.io.ByteArrayInputStream;
Expand All @@ -34,13 +35,14 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

/**
* A class which contains utilities to make OAuth2 specific calls.
*/
public class OAuthUtil {
public static String getAccessTokenByRefreshToken(CloseableHttpClient httpclient, String tokenUrl, String clientId,
String clientSecret, String refreshToken)
String clientSecret, String refreshToken, String grantType)
throws IOException {

URI uri;
Expand All @@ -49,7 +51,7 @@ public static String getAccessTokenByRefreshToken(CloseableHttpClient httpclient
.setParameter("client_id", clientId)
.setParameter("client_secret", clientSecret)
.setParameter("refresh_token", refreshToken)
.setParameter("grant_type", "refresh_token")
.setParameter("grant_type", grantType)
.build();
} catch (URISyntaxException e) {
throw new IllegalArgumentException("Failed to build token URI for OAuth2", e);
Expand Down Expand Up @@ -92,5 +94,29 @@ public static String getAccessTokenByServiceAccount(BaseHttpSourceConfig config)
}
return accessToken;
}

public static String getAccessTokenByClientCredentials(CloseableHttpClient httpclient, String tokenUrl,
String clientId, String clientSecret, String grantType)
throws IOException {
URI uri;
try {
uri = new URIBuilder(tokenUrl).setParameter("grant_type", grantType).build();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

define constants where ever any keyword getting used multiple times or has scope of getting used in future

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Constants are defined for both client credentials method and refresh token method.

} catch (URISyntaxException e) {
throw new IllegalArgumentException("Failed to build token URI for OAuth2", e);
}

HttpPost httppost = new HttpPost(uri);
httppost.addHeader(new BasicHeader("Authorization", "Basic " + getBase64EncodeValue(clientId, clientSecret)));
httppost.addHeader(new BasicHeader("Content-Type", "application/json"));
CloseableHttpResponse response = httpclient.execute(httppost);
String responseString = EntityUtils.toString(response.getEntity(), "UTF-8");

JsonElement jsonElement = JSONUtil.toJsonObject(responseString).get("access_token");
return jsonElement.getAsString();
}

private static String getBase64EncodeValue(String clientId, String clientSecret) {
return Base64.getEncoder().encodeToString((clientId + ":" + clientSecret).getBytes(StandardCharsets.UTF_8));
}
}

50 changes: 39 additions & 11 deletions widgets/HTTP-batchsource.json
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,18 @@
]
}
},
{
"widget-type": "select",
"label": "Grant Type",
"name": "grantType",
"widget-attributes" : {
"values": [
"refresh_token",
"client_credentials"
],
"default" : "refresh_token"
}
},
{
"widget-type": "textbox",
"label": "Auth URL",
Expand Down Expand Up @@ -684,27 +696,26 @@
},
"show": [
{
"name": "authUrl",
"type": "property"
},
{
"name": "tokenUrl",
"type": "property"
"widget-type": "textbox",
"label": "Token URL",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

label is not required here.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed the labels attribute according to the filters conditions.

"name": "tokenUrl"
},
{
"name": "clientId",
"type": "property"
"widget-type": "textbox",
"label": "Client ID",
"name": "clientId"
},
{
"name": "clientSecret",
"type": "property"
"widget-type": "password",
"label": "Client Secret",
"name": "clientSecret"
},
{
"name": "scopes",
"type": "property"
},
{
"name": "refreshToken",
"name": "grantType",
"type": "property"
}
]
Expand Down Expand Up @@ -780,6 +791,23 @@
"type": "property"
}
]
},
{
"name": "Grant Type Refresh Token",
"condition": {
"expression": "grantType == 'refresh_token' && authType == 'oAuth2'"
},
"show": [
{
"widget-type": "textbox",
"label": "Auth URL",
"name": "authUrl"
},
{
"name": "refreshToken",
"type": "property"
}
]
}
]
}