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

[PLUGIN-1741] SuccessFactors - OAuth2 Implementation #34

Merged

Conversation

Shubhangi-cs
Copy link
Contributor

@Shubhangi-cs Shubhangi-cs commented Jan 29, 2024

SuccessFactors OAuth2 Feature Implemenataion

Jira : PLUGIN-1741

Description

Succfactors currently uses basic auth where are user can enter username and password for auth. This PR adds a new option to let user use OAuth for auth.

What is assertion token and auth token ?

  • Assesertion Token
    • A Base64 encoded xml that contains metadata about the auth token, signed by a private key to as proof of ownership, this is used to authenticate while generating the auth token.
  • Auth token
    • A token generated using assertion token and OAuth backchanel flow that can be used as a bearer token to authenticate user with successfactors APIs.

UI Field

  • Modified SuccessFactors-batchsource.json
  • Modified SuccessFactors-connector.json

New Fields added

  • Authentication Type
    • Let's user toggle between basic auth (default) or OAuth2
  • Assertion Token Type
    • Let's the user either use their own assertion token or creat one on the fly
  • Token URL
  • Client ID
  • Private Key
  • Expire Assertion Token In (Minutes)
  • User ID
  • Company ID
  • Assertion Token
image image image

Docs

  • Modified SuccessFactors-batchsource.md
  • Modified SuccessFactors-connector.md
image

Code change

  • Added SuccessFactorsAccessToken.java
  • Modified ResourceConstants.java
  • Modified SuccessFactorsConnectorConfig.java
  • Modified SuccessFactorsSource.java
  • Modified SuccessFactorsPluginConfig.java
  • Modified SuccessFactorsService.java
  • Modified SuccessFactorsTransporter.java

Unit Tests

  • Modified SuccessFactorsConnectorTest.java
  • Modified SuccessFactorsSourceTest.java
  • Modified SuccessFactorsPluginConfigTest.java
  • Modified SuccessFactorsInputFormatTest.java
  • Modified SuccessFactorsSchemaGeneratorTest.java
  • Modified RuntimeFunctionalForAssociatedEntityTest.java
  • Modified RuntimeFunctionalTest.java
  • Modified SuccessFactorsTransporterTest.java
  • Modified SuccessFactorsUrlContainerTest.java

Sanity Tests

  • Tested pipeline with OAuth2 creds
  • Tested pipeline with proxy and OAuth2
  • Tested pipeline with Enter Token and Create Token Modes

@Shubhangi-cs Shubhangi-cs force-pushed the Oauth2_Implementation branch 2 times, most recently from ed6fb11 to 6989161 Compare February 2, 2024 06:54
@itsankit-google itsankit-google self-requested a review April 3, 2024 07:56
Copy link
Member

@itsankit-google itsankit-google left a comment

Choose a reason for hiding this comment

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

Please rebase the changes, resolve the conflicts and ensure build is green.

@@ -0,0 +1,391 @@
/*
* Copyright © 2022 Cask Data, Inc.
Copy link
Member

Choose a reason for hiding this comment

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

please update year in the license.

Copy link
Contributor

Choose a reason for hiding this comment

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

Year update to 2025

pom.xml Outdated
Comment on lines 338 to 388
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${httpclient.version}</version>
</dependency>
<dependency>
<groupId>org.opensaml</groupId>
<artifactId>xmltooling</artifactId>
<version>1.4.4</version>
</dependency>
<dependency>
<groupId>org.opensaml</groupId>
<artifactId>openws</artifactId>
<version>1.5.4</version>
</dependency>
<dependency>
<groupId>org.opensaml</groupId>
<artifactId>opensaml</artifactId>
<version>2.6.4</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
<dependency>
<groupId>xml-security</groupId>
<artifactId>xmlsec</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.5</version>
<type>pom</type>
</dependency>
Copy link
Member

Choose a reason for hiding this comment

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

How are the versions of these dependencies decided?

Is the same code being used somewhere in any other existing plugin?

Please add comments for every dependency where it is used.

Copy link
Contributor

Choose a reason for hiding this comment

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

We only need opensaml for which we are using 2.6.4 as this is the latest version on oss.sonatype.
I have removed all the other dependencies.

Comment on lines 103 to 105
"property": "authType",
"operator": "equal to",
"value": "basicAuth"
Copy link
Member

Choose a reason for hiding this comment

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

authType will be null in existing pipelines since it is a newly added config.

We should default to basicAuth when authType is also null.

Copy link
Contributor

Choose a reason for hiding this comment

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

Does "equal to" with will "null" ?
Can you provide reference to this.

Copy link
Member

@itsankit-google itsankit-google Jan 3, 2025

Choose a reason for hiding this comment

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

you can use filter as we do for Connection widget in other plugins

Copy link
Contributor

Choose a reason for hiding this comment

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

Updated

{
  "name": "basicAuth",
  "condition": {
    "expression": "authType == 'basicAuth' || authType == 'null'"
  },
  "show": [
    {
      "name": "username",
      "type": "property"
    },
    {
      "name": "password",
      "type": "property"
    }
  ]
}

Comment on lines 416 to 418
tokenURL, clientId, privateKey, userId, samlUsername, assertionToken,
companyId, authType, assertionTokenType, filterOption, selectOption,
expandOption, additionalQueryParameters, paginationType);
Copy link
Member

Choose a reason for hiding this comment

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

indentation looks off here.

Copy link
Contributor

Choose a reason for hiding this comment

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

Fixed !

Comment on lines 162 to 183
if (config.getConnection().getAuthType().equals(SuccessFactorsConnectorConfig.BASIC_AUTH)) {
failureCollector.addFailure(errMsg, null).withConfigProperty(SuccessFactorsPluginConfig.UNAME);
failureCollector.addFailure(errMsg, null).withConfigProperty(SuccessFactorsPluginConfig.PASSWORD);
} else {
failureCollector.addFailure(errMsg, null).withConfigProperty(SuccessFactorsConnectorConfig.COMPANY_ID);
failureCollector.addFailure(errMsg, null).withConfigProperty(SuccessFactorsConnectorConfig.CLIENT_ID);
if (config.getConnection().getAssertionTokenType().equals(SuccessFactorsConnectorConfig.ENTER_TOKEN)) {
failureCollector.addFailure(errMsg, null).
withConfigProperty(SuccessFactorsConnectorConfig.ASSERTION_TOKEN);
} else {
failureCollector.addFailure(errMsg, null).withConfigProperty(SuccessFactorsConnectorConfig.PRIVATE_KEY);
failureCollector.addFailure(errMsg, null).withConfigProperty(SuccessFactorsConnectorConfig.USER_ID);
failureCollector.addFailure(errMsg, null).withConfigProperty(SuccessFactorsConnectorConfig.TOKEN_URL);
Copy link
Member

Choose a reason for hiding this comment

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

constants should always be used first in java to avoid NPE in equals condition.

For example,

if (SuccessFactorsConnectorConfig.BASIC_AUTH.equals(config.getConnection().getAuthType())) {....}

Copy link
Contributor

Choose a reason for hiding this comment

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

Updated, reversed all equal checks to have constant first to avoid NPE.

Comment on lines 370 to 502
this.authType = authType;
return this;
Copy link
Member

Choose a reason for hiding this comment

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

authType will be null for existing pipelines.

It should default to BASIC_AUTH in that case.

Copy link
Contributor

Choose a reason for hiding this comment

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

Updated !

  • Default to basic auth if authType is not set for backward compatibility
this.authType = Strings.isNullOrEmpty(authType) ? SuccessFactorsConnectorConfig.BASIC_AUTH : authType;

@psainics psainics self-assigned this Jan 3, 2025
@psainics psainics changed the title [Plugin-1741] SuccessFactors - OAuth2 Implementation [PLUGIN-1741] SuccessFactors - OAuth2 Implementation Jan 3, 2025
Copy link
Member

@itsankit-google itsankit-google left a comment

Choose a reason for hiding this comment

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

please also add unit tests for newly added configs for oauth2.

if (SuccessFactorsUtil.isNullOrEmpty(getPassword()) && !containsMacro(PASSWORD)) {
String errMsg = ResourceConstants.ERR_MISSING_PARAM_PREFIX.getMsgForKey(SAP_SUCCESSFACTORS_PASSWORD);
failureCollector.addFailure(errMsg, COMMON_ACTION).withConfigProperty(PASSWORD);
if (BASIC_AUTH.equals(this.getAuthType())) {
Copy link
Member

Choose a reason for hiding this comment

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

nit: getAuthType()

Copy link
Contributor

Choose a reason for hiding this comment

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

Updated !

String errMsg = ResourceConstants.ERR_MISSING_PARAM_PREFIX.getMsgForKey(SAP_SUCCESSFACTORS_PASSWORD);
failureCollector.addFailure(errMsg, COMMON_ACTION).withConfigProperty(PASSWORD);
if (BASIC_AUTH.equals(this.getAuthType())) {
if (Strings.isNullOrEmpty(getUsername()) && !containsMacro(UNAME)) {
Copy link
Member

Choose a reason for hiding this comment

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

check containsMacro() first for all configs.

Copy link
Contributor

Choose a reason for hiding this comment

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

Authentication Type is not macro

Copy link
Member

@itsankit-google itsankit-google Jan 6, 2025

Choose a reason for hiding this comment

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

The comment was all other configs which are macro to change the order of conditions, for example:

if (!containsMacro(UNAME) && Strings.isNullOrEmpty(getUsername()))
.........

Copy link
Contributor

Choose a reason for hiding this comment

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

Updated, i misunderstood the request !

@@ -46,6 +46,7 @@
import io.cdap.plugin.successfactors.source.input.SuccessFactorsPartitionBuilder;
import io.cdap.plugin.successfactors.source.service.SuccessFactorsService;
import io.cdap.plugin.successfactors.source.transport.SuccessFactorsTransporter;

Copy link
Member

Choose a reason for hiding this comment

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

nit: remove empty line

Copy link
Contributor

Choose a reason for hiding this comment

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

Removed !

@@ -57,6 +58,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

Copy link
Member

Choose a reason for hiding this comment

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

nit: remove empty line

Copy link
Contributor

Choose a reason for hiding this comment

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

Removed !

Comment on lines 158 to 165
.handle(RetryableException.class)
.withBackoff(Duration.ofSeconds(initialRetryDuration),
Duration.ofSeconds(maxRetryDuration), retryMultiplier)
.withMaxRetries(maxRetryCount)
.onRetry(event -> LOG.debug("Retrying SapTransportCall. Retry count: {}", event.getAttemptCount()))
.onSuccess(event -> LOG.debug("SapTransportCall executed successfully."))
.onRetriesExceeded(event -> LOG.error("Retry limit reached for SapTransportCall."))
.build();
Copy link
Member

Choose a reason for hiding this comment

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

revert unintended changes.

Copy link
Contributor

Choose a reason for hiding this comment

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

Reverted !

public String getUserId() {
return userId;
}

public String getBaseURL() {
return baseURL;
}

public void validateBasicCredentials(FailureCollector failureCollector) {
Copy link
Member

Choose a reason for hiding this comment

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

This function should be renamed to validateAuthCredentials

Copy link
Contributor

Choose a reason for hiding this comment

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

Done !

@@ -51,7 +51,6 @@
import org.apache.hadoop.mapreduce.Job;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Copy link
Member

Choose a reason for hiding this comment

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

please revert unintended change

Copy link
Contributor

Choose a reason for hiding this comment

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

Updated !

Copy link
Member

@itsankit-google itsankit-google left a comment

Choose a reason for hiding this comment

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

minor comments otherwise LGTM. Please squash commits before merge.

Would be good to also run existing e2e tests once succesfuly before merge.

@@ -22,6 +22,7 @@
import io.cdap.plugin.successfactors.source.metadata.TestSuccessFactorsUtil;
import io.cdap.plugin.successfactors.source.service.SuccessFactorsService;
import io.cdap.plugin.successfactors.source.transport.SuccessFactorsTransporter;

Copy link
Member

Choose a reason for hiding this comment

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

nit: remove empty line

Copy link
Contributor

Choose a reason for hiding this comment

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

Updated !

@psainics psainics force-pushed the Oauth2_Implementation branch 2 times, most recently from a7772ea to f545134 Compare January 8, 2025 07:04
@psainics psainics force-pushed the Oauth2_Implementation branch from f545134 to 6e7d151 Compare January 8, 2025 07:05
@psainics psainics merged commit f833826 into data-integrations:develop Jan 8, 2025
3 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants