Skip to content

Commit

Permalink
Rework
Browse files Browse the repository at this point in the history
  • Loading branch information
Shubhangi-cs committed Jan 16, 2024
1 parent 7708327 commit a8b0b98
Show file tree
Hide file tree
Showing 9 changed files with 123 additions and 89 deletions.
6 changes: 3 additions & 3 deletions docs/SuccessFactors-batchsource.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ You also can use the macro function ${conn(connection-name)}.
* **Basic Authentication**
**SAP SuccessFactors Logon Username (M)**: SAP SuccessFactors Logon Username for user authentication.
**SAP SuccessFactors Logon Password (M)**: SAP SuccessFactors Logon password for user authentication.
* **OAuth2**
**Assertion Token Type:** Assertion token can be entered or can be created using the required parameters.
* **OAuth 2.0**
**Client Id:** Client Id required to generate the token.
**Company Id:** Company Id required to generate the token.
**Company Id:** Company Id required to generate the token.
**Assertion Token Type:** Assertion token can be entered or can be created using the required parameters.
* **Enter Token**
**Assertion Token:** Assertion token used to generate the access token.
* **Create Token**
Expand Down
25 changes: 12 additions & 13 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

<groupId>io.cdap.plugin.successfactors</groupId>
<artifactId>successfactors-plugins</artifactId>
<version>1.2.1-SNAPSHOT</version>
<version>1.2.2-SNAPSHOT</version>
<packaging>jar</packaging>

<properties>
Expand All @@ -41,6 +41,7 @@
<junit.version>4.12</junit.version>
<gcs.client.version>2.0.0</gcs.client.version>
<okhttp3.version>4.9.1</okhttp3.version>
<httpclient.version>4.5.13</httpclient.version>
<apache.olingo.v2>2.0.0</apache.olingo.v2>
<wiremock.version>2.27.2</wiremock.version>
<hydrator.version>2.7.0</hydrator.version>
Expand Down Expand Up @@ -337,24 +338,29 @@
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version> <!-- Use the latest version available -->
<version>${httpclient.version}</version> <!-- Use the latest version available -->
</dependency>
<dependency>
<groupId>org.opensaml</groupId>
<artifactId>xmltooling</artifactId>
<version>1.4.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
<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>
<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
<dependency>
<groupId>xml-security</groupId>
<artifactId>xmlsec</artifactId>
Expand Down Expand Up @@ -385,13 +391,6 @@
<version>1.5</version>
<type>pom</type>
</dependency>

<dependency>
<groupId>org.opensaml</groupId>
<artifactId>openws</artifactId>
<version>1.5.4</version>
</dependency>

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,16 +82,28 @@
/**
* AccessToken class
*/
public class AccessToken {
private static final Logger LOG = LoggerFactory.getLogger(AccessToken.class);
public class SuccessFactorsAccessToken {
private static final Logger LOG = LoggerFactory.getLogger(SuccessFactorsAccessToken.class);
private final SuccessFactorsConnectorConfig config;
private final Gson gson = new Gson();


public AccessToken(SuccessFactorsConnectorConfig config) {
public SuccessFactorsAccessToken(SuccessFactorsConnectorConfig config) {
this.config = config;
}

/**
* Generates a signed SAML assertion for authentication purposes.
*
* @param clientId The client ID associated with the application.
* @param username The username of the user for whom the assertion is generated.
* @param tokenUrl The URL for obtaining the authentication token.
* @param privateKeyString The private key used for signing the assertion.
* @param expireInMinutes The validity period of the assertion in minutes.
* @param userUserNameAsUserId A boolean indicating whether to use the username as the User ID in the assertion.
* @return The signed SAML assertion as a string.
* @throws Exception If an error occurs during the generation or signing of the SAML assertion.
*/
public static String generateSignedSAMLAssertion(String clientId, String username, String tokenUrl,
String privateKeyString, int expireInMinutes,
boolean userUserNameAsUserId) throws Exception {
Expand All @@ -105,6 +117,17 @@ public static String generateSignedSAMLAssertion(String clientId, String usernam
return signedAssertion;
}

/**
* Builds a default SAML assertion with specified parameters for authentication purposes.
*
* @param clientId The client ID associated with the application.
* @param userId The user ID for whom the assertion is generated.
* @param tokenUrl The URL for obtaining the authentication token.
* @param expireInMinutes The validity period of the assertion in minutes.
* @param userUserNameAsUserId A boolean indicating whether to use the username as the User ID in the assertion.
* @return The constructed SAML assertion.
* @throws RuntimeException if an error occurs during the construction of the SAML assertion.
*/
private static Assertion buildDefaultAssertion(String clientId, String userId, String tokenUrl, int expireInMinutes,
boolean userUserNameAsUserId) {
try {
Expand Down Expand Up @@ -191,7 +214,6 @@ private static Assertion buildDefaultAssertion(String clientId, String userId, S

/**
* helper method to create open saml objects.
*
* @param cls class type
* @param qname qualified name
* @param <T> class type
Expand All @@ -214,7 +236,6 @@ private static Attribute createAttribute(String name, String value) {
}

private static Conditions buildConditions(DateTime currentTime, int expireInMinutes) {

Conditions conditions = create(Conditions.class, Conditions.DEFAULT_ELEMENT_NAME);
conditions.setNotBefore(currentTime.minusMinutes(10));
conditions.setNotOnOrAfter(currentTime.plusMinutes(expireInMinutes));
Expand All @@ -239,6 +260,17 @@ private static String getSAMLAssertionString(Assertion assertion) {
}
}

/**
* Signs a SAML assertion using the provided private key.
*
* @param assertion The unsigned SAML assertion to be signed.
* @param privateKey The private key used for signing the assertion.
* @return The signed SAML assertion.
* @throws Exception If an error occurs during the signing process.
* - If the SAML assertion is already signed.
* - If an invalid X.509 private key is provided.
* - If there is a failure in signing the SAML2 assertion.
*/
private static Assertion sign(Assertion assertion, PrivateKey privateKey) throws Exception {
BasicX509Credential credential = new BasicX509Credential();
credential.setPrivateKey(privateKey);
Expand Down Expand Up @@ -272,30 +304,25 @@ private static Assertion sign(Assertion assertion, PrivateKey privateKey) throws
}

private static PrivateKey generatePrivateKey(String privateKeyString) {
KeyFactory keyFactory = null;
try {
keyFactory = KeyFactory.getInstance("RSA");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e.getMessage(), e);
}
String pk2 = privateKeyString;
try {
pk2 = new String(Base64.decodeBase64(pk2), "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e.getMessage(), e);
}
String[] strs = pk2.split("###");
if (null != strs && strs.length == 2) {
privateKeyString = strs[0];
}
PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyString));
PrivateKey privateKey = null;
try {
privateKey = keyFactory.generatePrivate(privateKeySpec);
} catch (InvalidKeySpecException e) {
throw new RuntimeException(e.getMessage(), e);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");

// Decode the base64-encoded private key string
String pk2 = new String(Base64.decodeBase64(privateKeyString), "UTF-8");

// Extract the actual private key string if it is in a format like "privateKey###additionalInfo"
String[] strs = pk2.split("###");
if (strs.length == 2) {
privateKeyString = strs[0];
}

// Generate the private key from the decoded key string
PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyString));
return keyFactory.generatePrivate(privateKeySpec);
} catch (NoSuchAlgorithmException | UnsupportedEncodingException | InvalidKeySpecException e) {
// Throw a runtime exception if an error occurs during the private key generation process
throw new RuntimeException("Error generating private key", e);
}
return privateKey;
}

public String getAssertionToken() throws Exception {
Expand All @@ -316,7 +343,8 @@ public String getAssertionToken() throws Exception {

String signedSAMLAssertion = generateSignedSAMLAssertion(clientId, userId, tokenUrl, privateKey,
expireInMinutes, useUserNameAsUserId);
LOG.info("The generated Signed SAML Assertion is:");
LOG.info("Signed SAML Assertion is generated");
LOG.debug("The generated Signed SAML Assertion is: {}", signedSAMLAssertion);
return signedSAMLAssertion;
}
} catch (Exception e) {
Expand All @@ -337,10 +365,10 @@ public String getAccessToken(String assertionToken) throws IOException {

// Build request body
StringBuilder body = new StringBuilder();
body.append("client_id" + "=" + config.getClientId());
body.append("&company_id" + "=" + config.getCompanyId());
body.append("&grant_type=urn:ietf:params:oauth:grant-type:saml2-bearer");
body.append("&assertion" + "=" + assertionToken);
body.append("client_id=").append(config.getClientId());
body.append("&company_id=").append(config.getCompanyId());
body.append("&grant_type=").append("urn:ietf:params:oauth:grant-type:saml2-bearer");
body.append("&assertion=").append(assertionToken);

// Set request entity
request.setEntity(new StringEntity(body.toString()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@
public class SuccessFactorsConnectorConfig extends PluginConfig {
public static final String PROPERTY_AUTH_TYPE = "authType";
public static final String ASSERTION_TOKEN_TYPE = "assertionTokenType";
public static final String BASIC_AUTH = "basicAuth";
public static final String OAUTH2 = "oAuth2";
public static final String ENTER_TOKEN = "enterToken";
public static final String CREATE_TOKEN = "createToken";
public static final String BASE_URL = "baseURL";
public static final String UNAME = "username";
public static final String PASSWORD = "password";
Expand Down Expand Up @@ -89,19 +93,19 @@ public class SuccessFactorsConnectorConfig extends PluginConfig {
@Nullable
@Name(CLIENT_ID)
@Macro
@Description("Client Id required to generate the token.")
@Description("Client Id to generate the token.")
private final String clientId;

@Nullable
@Name(PRIVATE_KEY)
@Macro
@Description("Private key required to generate the token.")
@Description("Private key to generate the token.")
private final String privateKey;

@Nullable
@Name(USER_ID)
@Macro
@Description("User Id required to generate the token.")
@Description("User Id to generate the token.")
private final String userId;

@Nullable
Expand All @@ -113,7 +117,7 @@ public class SuccessFactorsConnectorConfig extends PluginConfig {
@Nullable
@Name(COMPANY_ID)
@Macro
@Description("Company Id required to generate the token.")
@Description("Company Id to generate the token.")
private final String companyId;

@Macro
Expand Down Expand Up @@ -161,6 +165,11 @@ public String getCompanyId() {
return companyId;
}

@Nullable
public String getAssertionTokenType() {
return assertionTokenType;
}

@Nullable
public String getClientId() {
return clientId;
Expand All @@ -187,19 +196,23 @@ public String getBaseURL() {

public void validateBasicCredentials(FailureCollector failureCollector) {

if (authType.equals("basicAuth")) {
if (!SuccessFactorsUtil.isNotNullOrEmpty(getAuthType())) {
return;
}

if (authType.equals(BASIC_AUTH)) {

if (SuccessFactorsUtil.isNullOrEmpty(getUsername()) && !containsMacro(UNAME)) {
String errMsg = ResourceConstants.ERR_MISSING_PARAM_PREFIX.getMsgForKey(SAP_SUCCESSFACTORS_USERNAME);
failureCollector.addFailure(errMsg, COMMON_ACTION).withConfigProperty(UNAME);
}
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 (SuccessFactorsUtil.isNullOrEmpty(getPassword()) && !containsMacro(PASSWORD)) {
String errMsg = ResourceConstants.ERR_MISSING_PARAM_PREFIX.getMsgForKey(SAP_SUCCESSFACTORS_PASSWORD);
failureCollector.addFailure(errMsg, COMMON_ACTION).withConfigProperty(PASSWORD);
}

if (authType.equals("oAuth2")) {
}
if (authType.equals(OAUTH2)) {
if (SuccessFactorsUtil.isNullOrEmpty(getClientId()) && !containsMacro(CLIENT_ID)) {
String errMsg = ResourceConstants.ERR_MISSING_PARAM_PREFIX.getMsgForKey(CLIENT_ID);
failureCollector.addFailure(errMsg, COMMON_ACTION).withConfigProperty(CLIENT_ID);
Expand All @@ -209,14 +222,14 @@ public void validateBasicCredentials(FailureCollector failureCollector) {
failureCollector.addFailure(errMsg, COMMON_ACTION).withConfigProperty(COMPANY_ID);
}

if (assertionTokenType.equals("enterToken")) {
if (assertionTokenType.equals(ENTER_TOKEN)) {
if (SuccessFactorsUtil.isNullOrEmpty(getAssertionToken()) && !containsMacro(ASSERTION_TOKEN)) {
String errMsg = ResourceConstants.ERR_MISSING_PARAM_PREFIX.getMsgForKey(ASSERTION_TOKEN);
failureCollector.addFailure(errMsg, COMMON_ACTION).withConfigProperty(ASSERTION_TOKEN);
}
}

if (assertionTokenType.equals("createToken")) {
if (assertionTokenType.equals(CREATE_TOKEN)) {
if (SuccessFactorsUtil.isNullOrEmpty(getTokenURL()) && !containsMacro(TOKEN_URL)) {
String errMsg = ResourceConstants.ERR_MISSING_PARAM_PREFIX.getMsgForKey(TOKEN_URL);
failureCollector.addFailure(errMsg, COMMON_ACTION).withConfigProperty(TOKEN_URL);
Expand Down Expand Up @@ -258,6 +271,7 @@ public void validateConnection(FailureCollector collector) {
} catch (TransportException e) {
LOG.error("Unable to fetch the response", e);
collector.addFailure("Unable to call SuccessFatorsEntity", "Please check the values");
return;
}
if (responseContainer.getHttpStatusCode() == HttpURLConnection.HTTP_UNAUTHORIZED) {
String errMsg = ResourceConstants.ERR_INVALID_CREDENTIAL.getMsgForKey();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,10 +161,6 @@ public SuccessFactorsPluginConfig(String referenceName,
this.additionalQueryParameters = additionalQueryParameters;
}

//public String getAuthType() {
// return this.authType;
// }

@Nullable
public SuccessFactorsConnectorConfig getConnection() {
return connection;
Expand Down Expand Up @@ -375,22 +371,22 @@ public Builder authType(@Nullable String authType) {
return this;
}

public Builder setTokenURL(String tokenURL) {
public Builder setTokenURL(@Nullable String tokenURL) {
this.tokenURL = tokenURL;
return this;
}

public Builder setClientId(String clientId) {
public Builder setClientId(@Nullable String clientId) {
this.clientId = clientId;
return this;
}

public Builder setPrivateKey(String privateKey) {
public Builder setPrivateKey(@Nullable String privateKey) {
this.privateKey = privateKey;
return this;
}

public Builder setUserId(String userId) {
public Builder setUserId(@Nullable String userId) {
this.userId = userId;
return this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import io.cdap.cdap.api.data.schema.Schema;
import io.cdap.plugin.successfactors.common.exception.SuccessFactorsServiceException;
import io.cdap.plugin.successfactors.common.exception.TransportException;
import io.cdap.plugin.successfactors.common.util.AccessToken;
import io.cdap.plugin.successfactors.common.util.ExceptionParser;
import io.cdap.plugin.successfactors.common.util.ResourceConstants;
import io.cdap.plugin.successfactors.common.util.SuccessFactorsUtil;
Expand Down
Loading

0 comments on commit a8b0b98

Please sign in to comment.