Skip to content

Commit 3b9051e

Browse files
committed
Support for client credentials Grant type
1 parent 1a36f01 commit 3b9051e

28 files changed

Lines changed: 663 additions & 62 deletions

docs/Salesforce-batchsink.md

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,27 @@ You also can use the macro function ${conn(connection-name)}.
1616

1717
**Reference Name:** Name used to uniquely identify this sink for lineage, annotating metadata, etc.
1818

19-
**Username:** Salesforce username.
19+
**Grant Type:** Grant type to use for OAuth authentication. Supported values are 'password' and
20+
'client_credentials'. When set to 'client_credentials', only Consumer Key, Consumer Secret, and Login URL
21+
are required. Username, Password, and Security Token are not needed. Defaults to 'password' if not specified.
2022

21-
**Password:** Salesforce password.
23+
**Username:** Salesforce username. Required for 'password' grant type.
2224

23-
**Security Token:** Salesforce security token. If the password does not contain the security token, the plugin
24-
will append the token before authenticating with Salesforce.
25+
**Password:** Salesforce password. Required for 'password' grant type.
26+
27+
**Security Token:** Salesforce security token. If the password does not contain the security token, the plugin
28+
will append the token before authenticating with Salesforce. Only applicable for 'password' grant type.
2529

2630
**Consumer Key:** Application Consumer Key. This is also known as the OAuth client ID.
2731
A Salesforce connected application must be created in order to get a consumer key.
2832

2933
**Consumer Secret:** Application Consumer Secret. This is also known as the OAuth client secret.
3034
A Salesforce connected application must be created in order to get a client secret.
3135

32-
**Login URL:** Salesforce OAuth2 login URL.
36+
**Login URL:** Salesforce OAuth2 login URL. For the 'password' grant type, the default generic URL
37+
`https://login.salesforce.com/services/oauth2/token` can be used. For the 'client_credentials' grant type,
38+
you must provide your Salesforce instance-specific URL, for example
39+
`https://<your-instance>.my.salesforce.com/services/oauth2/token`.
3340

3441
**Connect Timeout:** Maximum time in milliseconds to wait for connection initialization before it times out.
3542

docs/Salesforce-batchsource.md

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,27 @@ Configuration
1818

1919
**Reference Name:** Name used to uniquely identify this source for lineage, annotating metadata, etc.
2020

21-
**Username:** Salesforce username.
21+
**Grant Type:** Grant type to use for OAuth authentication. Supported values are 'password' and
22+
'client_credentials'. When set to 'client_credentials', only Consumer Key, Consumer Secret, and Login URL
23+
are required. Username, Password, and Security Token are not needed. Defaults to 'password' if not specified.
2224

23-
**Password:** Salesforce password.
25+
**Username:** Salesforce username. Required for 'password' grant type.
2426

25-
**Security Token:** Salesforce security token. If the password does not contain the security token the plugin,
26-
will append the token before authenticating with Salesforce.
27+
**Password:** Salesforce password. Required for 'password' grant type.
28+
29+
**Security Token:** Salesforce security token. If the password does not contain the security token the plugin,
30+
will append the token before authenticating with Salesforce. Only applicable for 'password' grant type.
2731

2832
**Consumer Key:** Application Consumer Key. This is also known as the OAuth client ID.
2933
A Salesforce connected application must be created in order to get a consumer key.
3034

3135
**Consumer Secret:** Application Consumer Secret. This is also known as the OAuth client secret.
3236
A Salesforce connected application must be created in order to get a client secret.
3337

34-
**Login URL:** Salesforce OAuth2 login URL.
38+
**Login URL:** Salesforce OAuth2 login URL. For the 'password' grant type, the default generic URL
39+
`https://login.salesforce.com/services/oauth2/token` can be used. For the 'client_credentials' grant type,
40+
you must provide your Salesforce instance-specific URL, for example
41+
`https://<your-instance>.my.salesforce.com/services/oauth2/token`.
3542

3643
**Connect Timeout:** Maximum time in milliseconds to wait for connection initialization before it times out.
3744

docs/Salesforce-connector.md

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,27 @@ Properties
1010

1111
**Description:** Description of the connection.
1212

13-
**Username:** Salesforce username.
13+
**Grant Type:** Grant type to use for OAuth authentication. Supported values are 'password' and
14+
'client_credentials'. When set to 'client_credentials', only Consumer Key, Consumer Secret, and Login URL
15+
are required. Username, Password, and Security Token are not needed. Defaults to 'password' if not specified.
1416

15-
**Password:** Salesforce password.
17+
**Username:** Salesforce username. Required for 'password' grant type.
18+
19+
**Password:** Salesforce password. Required for 'password' grant type.
1620

1721
**Security Token:** Salesforce security token. If the password does not contain the security token, the plugin
18-
will append the token before authenticating with Salesforce.
22+
will append the token before authenticating with Salesforce. Only applicable for 'password' grant type.
1923

2024
**Consumer Key:** Application Consumer Key. This is also known as the OAuth client ID.
2125
A Salesforce connected application must be created in order to get a consumer key.
2226

2327
**Consumer Secret:** Application Consumer Secret. This is also known as the OAuth client secret.
2428
A Salesforce connected application must be created in order to get a client secret.
2529

26-
**Login URL:** Salesforce OAuth2 login URL.
30+
**Login URL:** Salesforce OAuth2 login URL. For the 'password' grant type, the default generic URL
31+
`https://login.salesforce.com/services/oauth2/token` can be used. For the 'client_credentials' grant type,
32+
you must provide your Salesforce instance-specific URL, for example
33+
`https://<your-instance>.my.salesforce.com/services/oauth2/token`.
2734

2835
**Connect Timeout:** Maximum time in milliseconds to wait for connection initialization before it times out.
2936

docs/Salesforce-streamingsource.md

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,27 @@ Configuration
2121

2222
**Reference Name:** Name used to uniquely identify this source for lineage, annotating metadata, etc.
2323

24-
**Username:** Salesforce username.
24+
**Grant Type:** Grant type to use for OAuth authentication. Supported values are 'password' and
25+
'client_credentials'. When set to 'client_credentials', only Consumer Key, Consumer Secret, and Login URL
26+
are required. Username, Password, and Security Token are not needed. Defaults to 'password' if not specified.
2527

26-
**Password:** Salesforce password.
28+
**Username:** Salesforce username. Required for 'password' grant type.
2729

28-
**Security Token:** Salesforce security token. If the password does not contain the security token, the plugin
29-
will append the token before authenticating with Salesforce.
30+
**Password:** Salesforce password. Required for 'password' grant type.
31+
32+
**Security Token:** Salesforce security token. If the password does not contain the security token, the plugin
33+
will append the token before authenticating with Salesforce. Only applicable for 'password' grant type.
3034

3135
**Consumer Key:** Application Consumer Key. This is also known as the OAuth client ID.
3236
A Salesforce connected application must be created in order to get a consumer key.
3337

3438
**Consumer Secret:** Application Consumer Secret. This is also known as the OAuth client secret.
3539
A Salesforce connected application must be created in order to get a client secret.
3640

37-
**Login URL:** Salesforce OAuth2 login URL.
41+
**Login URL:** Salesforce OAuth2 login URL. For the 'password' grant type, the default generic URL
42+
`https://login.salesforce.com/services/oauth2/token` can be used. For the 'client_credentials' grant type,
43+
you must provide your Salesforce instance-specific URL, for example
44+
`https://<your-instance>.my.salesforce.com/services/oauth2/token`.
3845

3946
**Connect Timeout:** Maximum time in milliseconds to wait for connection initialization before it times out.
4047

docs/SalesforceMultiObjects-batchsource.md

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,27 @@ Configuration
1818

1919
**Reference Name:** Name used to uniquely identify this source for lineage, annotating metadata, etc.
2020

21-
**Username:** Salesforce username.
21+
**Grant Type:** Grant type to use for OAuth authentication. Supported values are 'password' and
22+
'client_credentials'. When set to 'client_credentials', only Consumer Key, Consumer Secret, and Login URL
23+
are required. Username, Password, and Security Token are not needed. Defaults to 'password' if not specified.
2224

23-
**Password:** Salesforce password.
25+
**Username:** Salesforce username. Required for 'password' grant type.
2426

25-
**Security Token:** Salesforce security token. If the password does not contain the security token, the plugin
26-
will append the token before authenticating with Salesforce.
27+
**Password:** Salesforce password. Required for 'password' grant type.
28+
29+
**Security Token:** Salesforce security token. If the password does not contain the security token, the plugin
30+
will append the token before authenticating with Salesforce. Only applicable for 'password' grant type.
2731

2832
**Consumer Key:** Application Consumer Key. This is also known as the OAuth client ID.
2933
A Salesforce connected application must be created in order to get a consumer key.
3034

3135
**Consumer Secret:** Application Consumer Secret. This is also known as the OAuth client secret.
3236
A Salesforce connected application must be created in order to get a client secret.
3337

34-
**Login URL:** Salesforce OAuth2 login URL.
38+
**Login URL:** Salesforce OAuth2 login URL. For the 'password' grant type, the default generic URL
39+
`https://login.salesforce.com/services/oauth2/token` can be used. For the 'client_credentials' grant type,
40+
you must provide your Salesforce instance-specific URL, for example
41+
`https://<your-instance>.my.salesforce.com/services/oauth2/token`.
3542

3643
**Connect Timeout:** Maximum time in milliseconds to wait for connection initialization before time out.
3744

src/main/java/io/cdap/plugin/salesforce/SalesforceConnectionUtil.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ public static OAuthInfo getOAuthInfo(SalesforceConnectorInfo config, FailureColl
123123
if (!config.canAttemptToEstablishConnection()) {
124124
return null;
125125
}
126+
config.validateAuthenticationFields(collector);
126127
OAuthInfo oAuthInfo = null;
127128
try {
128129
oAuthInfo = Authenticator.getOAuthInfo(config.getAuthenticatorCredentials());

src/main/java/io/cdap/plugin/salesforce/SalesforceConstants.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package io.cdap.plugin.salesforce;
1717

1818
import io.cdap.cdap.api.plugin.PluginConfig;
19+
import io.cdap.plugin.salesforce.authenticator.AuthenticatorCredentials.GrantType;
1920

2021
import java.util.Arrays;
2122
import java.util.Collections;
@@ -65,11 +66,15 @@ public class SalesforceConstants {
6566
public static final String CONFIG_MAX_RETRY_DURATION = "mapred.salesforce.maxRetryDuration";
6667
public static final String CONFIG_MAX_RETRY_COUNT = "mapred.salesforce.maxRetryCount";
6768
public static final String CONFIG_RETRY_REQUIRED = "mapred.salesforce.retryOnBackendError";
69+
public static final String CONFIG_GRANT_TYPE = "mapred.salesforce.grantType";
6870

6971
public static final String PROPERTY_PROXY_URL = "proxyUrl";
7072
public static final String CONFIG_PROXY_URL = "mapred.salesforce.proxyUrl";
7173
public static final String REGEX_PROXY_URL = "^(?i)(https?)://.*$";
7274

75+
public static final String PROPERTY_AUTHENTICATION_GRANT_TYPE = "authenticationGrantType";
76+
public static final GrantType DEFAULT_GRANT_TYPE = GrantType.PASSWORD;
77+
7378
public static final String PROPERTY_MAX_RETRY_TIME_IN_MINS = "cdap.streaming.maxRetryTimeInMins";
7479
public static final long DEFAULT_MAX_RETRY_TIME_IN_MINS = 360L;
7580

src/main/java/io/cdap/plugin/salesforce/plugin/SalesforceConnectorBaseConfig.java

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package io.cdap.plugin.salesforce.plugin;
1717

18+
import com.google.common.base.Strings;
1819
import com.sforce.ws.ConnectionException;
1920
import io.cdap.cdap.api.annotation.Description;
2021
import io.cdap.cdap.api.annotation.Macro;
@@ -24,6 +25,7 @@
2425
import io.cdap.plugin.salesforce.SalesforceConnectionUtil;
2526
import io.cdap.plugin.salesforce.SalesforceConstants;
2627
import io.cdap.plugin.salesforce.authenticator.AuthenticatorCredentials;
28+
import io.cdap.plugin.salesforce.authenticator.AuthenticatorCredentials.GrantType;
2729

2830
import javax.annotation.Nullable;
2931

@@ -32,6 +34,12 @@
3234
*/
3335
public class SalesforceConnectorBaseConfig extends PluginConfig {
3436

37+
@Name(SalesforceConstants.PROPERTY_AUTHENTICATION_GRANT_TYPE)
38+
@Description("Salesforce authentication grant type: basic or client credentials")
39+
@Nullable
40+
@Macro
41+
protected String authenticationGrantType;
42+
3543
@Nullable
3644
@Name(SalesforceConstants.PROPERTY_PROXY_URL)
3745
@Description("Proxy URL. Must contain a protocol, address and port.")
@@ -118,7 +126,8 @@ public SalesforceConnectorBaseConfig(@Nullable String consumerKey,
118126
@Nullable Long initialRetryDuration,
119127
@Nullable Long maxRetryDuration,
120128
@Nullable Integer maxRetryCount,
121-
@Nullable Boolean retryOnBackendError) {
129+
@Nullable Boolean retryOnBackendError,
130+
@Nullable String authenticationGrantType) {
122131
this.consumerKey = consumerKey;
123132
this.consumerSecret = consumerSecret;
124133
this.username = username;
@@ -132,6 +141,16 @@ public SalesforceConnectorBaseConfig(@Nullable String consumerKey,
132141
this.maxRetryDuration = maxRetryDuration;
133142
this.retryOnBackendError = retryOnBackendError;
134143
this.maxRetryCount = maxRetryCount;
144+
this.authenticationGrantType = authenticationGrantType;
145+
}
146+
147+
public GrantType getAuthenticationGrantType() {
148+
if (!Strings.isNullOrEmpty(authenticationGrantType) &&
149+
authenticationGrantType.equals(GrantType.CLIENT_CREDENTIALS.getType())) {
150+
return GrantType.CLIENT_CREDENTIALS;
151+
}
152+
// Default auth, handles null case when upgrading pipeline
153+
return SalesforceConstants.DEFAULT_GRANT_TYPE;
135154
}
136155

137156
@Nullable
@@ -232,4 +251,55 @@ public String getProxyUrl() {
232251
return proxyUrl;
233252
}
234253

254+
/**
255+
* Validates that required authentication fields are present based on the selected OAuth grant type.
256+
* For PASSWORD grant type: consumerKey, consumerSecret, username, password, and loginUrl are required.
257+
* For CLIENT_CREDENTIALS grant type: consumerKey, consumerSecret, and loginUrl are required.
258+
*
259+
* @param collector the failure collector to report validation errors
260+
*/
261+
public void validateAuthenticationFields(FailureCollector collector) {
262+
if (containsMacro(SalesforceConstants.PROPERTY_AUTHENTICATION_GRANT_TYPE)) {
263+
return;
264+
}
265+
266+
GrantType grantType = getAuthenticationGrantType();
267+
268+
// Fields required for all grant types
269+
if (!containsMacro(SalesforceConstants.PROPERTY_CONSUMER_KEY) && Strings.isNullOrEmpty(consumerKey)) {
270+
collector.addFailure("Consumer Key is required for authentication.",
271+
"Please provide the Consumer Key from your Salesforce connected app.")
272+
.withConfigProperty(SalesforceConstants.PROPERTY_CONSUMER_KEY);
273+
}
274+
if (!containsMacro(SalesforceConstants.PROPERTY_CONSUMER_SECRET) && Strings.isNullOrEmpty(consumerSecret)) {
275+
collector.addFailure("Consumer Secret is required for authentication.",
276+
"Please provide the Consumer Secret from your Salesforce connected app.")
277+
.withConfigProperty(SalesforceConstants.PROPERTY_CONSUMER_SECRET);
278+
}
279+
if (!containsMacro(SalesforceConstants.PROPERTY_LOGIN_URL) && Strings.isNullOrEmpty(loginUrl)) {
280+
collector.addFailure("Login URL is required for authentication.",
281+
"Please provide the Salesforce login URL.")
282+
.withConfigProperty(SalesforceConstants.PROPERTY_LOGIN_URL);
283+
}
284+
285+
// Fields required only for PASSWORD grant type
286+
if (grantType == GrantType.PASSWORD) {
287+
if (!containsMacro(SalesforceConstants.PROPERTY_USERNAME) && Strings.isNullOrEmpty(username)) {
288+
collector.addFailure("Username is required for password grant type authentication.",
289+
"Please provide the Salesforce username.")
290+
.withConfigProperty(SalesforceConstants.PROPERTY_USERNAME);
291+
}
292+
if (!containsMacro(SalesforceConstants.PROPERTY_PASSWORD) && Strings.isNullOrEmpty(password)) {
293+
collector.addFailure("Password is required for password grant type authentication.",
294+
"Please provide the Salesforce password.")
295+
.withConfigProperty(SalesforceConstants.PROPERTY_PASSWORD);
296+
}
297+
if (!containsMacro(SalesforceConstants.PROPERTY_SECURITY_TOKEN) && Strings.isNullOrEmpty(securityToken)) {
298+
collector.addFailure("Security Token is required for password grant type authentication.",
299+
"Please provide the Salesforce security token.")
300+
.withConfigProperty(SalesforceConstants.PROPERTY_SECURITY_TOKEN);
301+
}
302+
}
303+
}
304+
235305
}

src/main/java/io/cdap/plugin/salesforce/plugin/SalesforceConnectorInfo.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import io.cdap.plugin.salesforce.SalesforceConnectionUtil;
2121
import io.cdap.plugin.salesforce.SalesforceConstants;
2222
import io.cdap.plugin.salesforce.authenticator.AuthenticatorCredentials;
23+
import io.cdap.plugin.salesforce.authenticator.AuthenticatorCredentials.GrantType;
2324
import io.cdap.plugin.salesforce.plugin.connector.SalesforceConnectorConfig;
2425

2526
import javax.annotation.Nullable;
@@ -103,6 +104,14 @@ public Boolean isRetryOnBackendError() {
103104
return config.isRetryOnBackendError();
104105
}
105106

107+
public GrantType getAuthenticationGrantType() {
108+
return config.getAuthenticationGrantType();
109+
}
110+
111+
public void validateAuthenticationFields(FailureCollector collector) {
112+
config.validateAuthenticationFields(collector);
113+
}
114+
106115
public void validate(FailureCollector collector, @Nullable OAuthInfo oAuthInfo) {
107116
try {
108117
validateConnection(oAuthInfo);
@@ -149,6 +158,7 @@ public boolean canAttemptToEstablishConnection() {
149158

150159
return !(config.containsMacro(SalesforceConstants.PROPERTY_CONSUMER_KEY)
151160
|| config.containsMacro(SalesforceConstants.PROPERTY_CONSUMER_SECRET)
161+
|| config.containsMacro(SalesforceConstants.PROPERTY_AUTHENTICATION_GRANT_TYPE)
152162
|| config.containsMacro(SalesforceConstants.PROPERTY_USERNAME)
153163
|| config.containsMacro(SalesforceConstants.PROPERTY_PASSWORD)
154164
|| config.containsMacro(SalesforceConstants.PROPERTY_LOGIN_URL)

src/main/java/io/cdap/plugin/salesforce/plugin/connector/SalesforceConnectorConfig.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,10 @@ public SalesforceConnectorConfig(@Nullable String consumerKey,
5151
@Nullable Long initialRetryDuration,
5252
@Nullable Long maxRetryDuration,
5353
@Nullable Integer maxRetryCount,
54-
@Nullable Boolean retryOnBackendError) {
54+
@Nullable Boolean retryOnBackendError,
55+
@Nullable String authenticationGrantType) {
5556
super(consumerKey, consumerSecret, username, password, loginUrl, securityToken, connectTimeout, readTimeout,
56-
proxyUrl, initialRetryDuration, maxRetryDuration, maxRetryCount, retryOnBackendError);
57+
proxyUrl, initialRetryDuration, maxRetryDuration, maxRetryCount, retryOnBackendError, authenticationGrantType);
5758
this.oAuthInfo = oAuthInfo;
5859
}
5960

0 commit comments

Comments
 (0)