Skip to content

Commit

Permalink
Proxy implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
Shubhangi-cs committed Dec 20, 2023
1 parent d3c06f2 commit 08482c0
Show file tree
Hide file tree
Showing 18 changed files with 283 additions and 62 deletions.
5 changes: 5 additions & 0 deletions docs/SuccessFactors-batchsource.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ You also can use the macro function ${conn(connection-name)}.
**SAP SuccessFactors Logon Password (M)**: SAP SuccessFactors Logon password for user authentication.
**SAP SuccessFactors Base URL (M)**: SAP SuccessFactors Base URL.

## Proxy Configuration
**Proxy URL:** Proxy URL. Must contain a protocol, address and port.
**Username:** Proxy username.
**Password:** Proxy password.


## Advance Option:

Expand Down
6 changes: 6 additions & 0 deletions docs/SuccessFactors-connector.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ Properties

**SAP SuccessFactors Base URL (M)**: SAP SuccessFactors Base URL.

**Proxy URL:** Proxy URL. Must contain a protocol, address and port.

**Username:** Proxy username.

**Password:** Proxy password.


Path of the connection
----------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,7 @@ public static String trim(String rawString) {
* @return SuccessFactorsService instance
*/
public static SuccessFactorsService getSuccessFactorsService(SuccessFactorsPluginConfig pluginConfig) {
SuccessFactorsTransporter transporter = new SuccessFactorsTransporter(pluginConfig.getConnection().getUsername(),
pluginConfig.getConnection().getPassword());
SuccessFactorsTransporter transporter = new SuccessFactorsTransporter(pluginConfig.getConnection());
SuccessFactorsService successFactorsService = new SuccessFactorsService(pluginConfig, transporter);
return successFactorsService;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,7 @@ public ConnectorSpec generateSpec(ConnectorContext connectorContext, ConnectorSp

List<String> listEntities() throws TransportException, IOException {
URL dataURL = HttpUrl.parse(config.getBaseURL()).newBuilder().build().url();
SuccessFactorsTransporter successFactorsHttpClient = new SuccessFactorsTransporter(config.getUsername(),
config.getPassword());
SuccessFactorsTransporter successFactorsHttpClient = new SuccessFactorsTransporter(config);
SuccessFactorsResponseContainer responseContainer = successFactorsHttpClient.callSuccessFactorsEntity
(dataURL, MediaType.APPLICATION_JSON, METADATA);
try (InputStream inputStream = responseContainer.getResponseStream()) {
Expand Down Expand Up @@ -225,8 +224,7 @@ private InputStream callEntityData(long top, String entityName)
URL dataURL = HttpUrl.parse(config.getBaseURL()).newBuilder().addPathSegment(entityName).
addQueryParameter(TOP_OPTION, String.valueOf(top)).addQueryParameter(SELECT_OPTION, selectFields.toString())
.build().url();
SuccessFactorsTransporter successFactorsHttpClient = new SuccessFactorsTransporter(config.getUsername(),
config.getPassword());
SuccessFactorsTransporter successFactorsHttpClient = new SuccessFactorsTransporter(config);
SuccessFactorsResponseContainer responseContainer = successFactorsHttpClient.callSuccessFactorsWithRetry(dataURL);

ExceptionParser.checkAndThrowException("", responseContainer);
Expand Down Expand Up @@ -255,8 +253,7 @@ SuccessFactorsEntityProvider fetchServiceMetadata(String entity) throws Transpor
private InputStream getMetaDataStream(String entity) throws TransportException, IOException {
URL metadataURL = HttpUrl.parse(config.getBaseURL()).newBuilder().addPathSegments(entity)
.addPathSegment(METADATACALL).build().url();
SuccessFactorsTransporter successFactorsHttpClient = new SuccessFactorsTransporter(config.getUsername(),
config.getPassword());
SuccessFactorsTransporter successFactorsHttpClient = new SuccessFactorsTransporter(config);
SuccessFactorsResponseContainer responseContainer = successFactorsHttpClient
.callSuccessFactorsEntity(metadataURL, MediaType.APPLICATION_XML, METADATA);
return responseContainer.getResponseStream();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@

import java.net.HttpURLConnection;
import java.net.URL;

import javax.annotation.Nullable;
import javax.ws.rs.core.MediaType;

/**
Expand All @@ -43,6 +45,9 @@ public class SuccessFactorsConnectorConfig extends PluginConfig {
public static final String BASE_URL = "baseURL";
public static final String UNAME = "username";
public static final String PASSWORD = "password";
public static final String PROPERTY_PROXY_URL = "proxyUrl";
public static final String PROPERTY_PROXY_USERNAME = "proxyUsername";
public static final String PROPERTY_PROXY_PASSWORD = "proxyPassword";
public static final String TEST = "TEST";
private static final String COMMON_ACTION = ResourceConstants.ERR_MISSING_PARAM_OR_MACRO_ACTION.getMsgForKey();
private static final String SAP_SUCCESSFACTORS_USERNAME = "SAP SuccessFactors Username";
Expand All @@ -65,10 +70,44 @@ public class SuccessFactorsConnectorConfig extends PluginConfig {
@Description("SuccessFactors Base URL.")
private final String baseURL;

public SuccessFactorsConnectorConfig(String username, String password, String baseURL) {
@Nullable
@Name(PROPERTY_PROXY_URL)
@Description("Proxy URL. Must contain a protocol, address and port.")
@Macro
protected String proxyUrl;

@Nullable
@Name(PROPERTY_PROXY_USERNAME)
@Description("Proxy username.")
@Macro
protected String proxyUsername;

@Nullable
@Name(PROPERTY_PROXY_PASSWORD)
@Description("Proxy password.")
@Macro
protected String proxyPassword;

public SuccessFactorsConnectorConfig(String username, String password, String baseURL, String proxyUrl,
String proxyUsername, String proxyPassword) {
this.username = username;
this.password = password;
this.baseURL = baseURL;
this.proxyUrl = proxyUrl;
this.proxyUsername = proxyUsername;
this.proxyPassword = proxyPassword;
}

public String getProxyUrl() {
return proxyUrl;
}

public String getProxyUsername() {
return proxyUsername;
}

public String getProxyPassword() {
return proxyPassword;
}

public String getUsername() {
Expand Down Expand Up @@ -109,7 +148,7 @@ public void validateBasicCredentials(FailureCollector failureCollector) {
* Method to validate the credential fields.
*/
public void validateConnection(FailureCollector collector) {
SuccessFactorsTransporter successFactorsHttpClient = new SuccessFactorsTransporter(getUsername(), getPassword());
SuccessFactorsTransporter successFactorsHttpClient = new SuccessFactorsTransporter(this);
URL testerURL = HttpUrl.parse(getBaseURL()).newBuilder().build().url();
SuccessFactorsResponseContainer responseContainer = null;
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,7 @@ public void prepareRun(BatchSourceContext context) throws Exception {
@Nullable
private Schema getOutputSchema(FailureCollector failureCollector) {
if (config.getConnection() != null) {
SuccessFactorsTransporter transporter = new SuccessFactorsTransporter(config.getConnection().getUsername(),
config.getConnection().getPassword());
SuccessFactorsTransporter transporter = new SuccessFactorsTransporter(config.getConnection());
SuccessFactorsService successFactorsServices = new SuccessFactorsService(config, transporter);
try {
//validate if the given parameters form a valid SuccessFactors URL.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ public class SuccessFactorsPluginConfig extends PluginConfig {
public static final String ENTITY_NAME = "entityName";
public static final String UNAME = "username";
public static final String PASSWORD = "password";
public static final String PROPERTY_PROXY_URL = "proxyUrl";
public static final String PROPERTY_PROXY_USERNAME = "proxyUsername";
public static final String PROPERTY_PROXY_PASSWORD = "proxyPassword";
private static final String REFERENCE_NAME = "referenceName";
private static final String REFERENCE_NAME_DESCRIPTION = "This will be used to uniquely identify this source/sink " +
"for lineage, annotating metadata, etc.";
Expand Down Expand Up @@ -135,12 +138,16 @@ public SuccessFactorsPluginConfig(String referenceName,
String associateEntityName,
@Nullable String username,
@Nullable String password,
@Nullable String proxyUrl,
@Nullable String proxyPassword,
@Nullable String proxyUsername,
@Nullable String filterOption,
@Nullable String selectOption,
@Nullable String expandOption,
@Nullable String additionalQueryParameters,
String paginationType) {
this.connection = new SuccessFactorsConnectorConfig(username, password, baseURL);
this.connection = new SuccessFactorsConnectorConfig(username, password, baseURL, proxyUrl, proxyPassword,
proxyUsername);
this.referenceName = referenceName;
this.entityName = entityName;
this.associateEntityName = associateEntityName;
Expand Down Expand Up @@ -214,7 +221,9 @@ public String getAdditionalQueryParameters() {
* @return boolean flag as per the check
*/
public boolean isSchemaBuildRequired() {
return !(containsMacro(UNAME) || containsMacro(PASSWORD) || containsMacro(BASE_URL) || containsMacro(ENTITY_NAME));
return !(containsMacro(UNAME) || containsMacro(PASSWORD) || containsMacro(BASE_URL) || containsMacro(ENTITY_NAME)
|| containsMacro(PROPERTY_PROXY_URL) || containsMacro(PROPERTY_PROXY_USERNAME)
|| containsMacro(PROPERTY_PROXY_USERNAME));
}

/**
Expand Down Expand Up @@ -300,6 +309,10 @@ public static class Builder {
private String expandOption;
private String paginationType;
private String additionalQueryParameters;
private String proxyUrl;
private String proxyUsername;
private String proxyPassword;


public Builder referenceName(String referenceName) {
this.referenceName = referenceName;
Expand Down Expand Up @@ -331,6 +344,19 @@ public Builder password(@Nullable String password) {
return this;
}

public Builder proxyUrl(@Nullable String proxyUrl) {
this.proxyUrl = proxyUrl;
return this;
}
public Builder proxyUsername(@Nullable String proxyUsername) {
this.proxyUsername = proxyUsername;
return this;
}
public Builder proxyPassword(@Nullable String proxyPassword) {
this.proxyPassword = proxyPassword;
return this;
}

public Builder filterOption(@Nullable String filterOption) {
this.filterOption = filterOption;
return this;
Expand All @@ -357,7 +383,8 @@ public Builder additionalQueryParameters(@Nullable String additionalQueryParamet
}

public SuccessFactorsPluginConfig build() {
return new SuccessFactorsPluginConfig(referenceName, baseURL, entityName, associateEntityName, username, password,
return new SuccessFactorsPluginConfig(referenceName, baseURL, entityName, associateEntityName, username,
password, proxyUrl, proxyUsername, proxyPassword,
filterOption, selectOption, expandOption, additionalQueryParameters,
paginationType);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,34 @@
import io.cdap.cdap.api.retry.RetryableException;
import io.cdap.plugin.successfactors.common.exception.TransportException;
import io.cdap.plugin.successfactors.common.util.ResourceConstants;
import io.cdap.plugin.successfactors.connector.SuccessFactorsConnectorConfig;
import okhttp3.Authenticator;
import okhttp3.Credentials;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.Route;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

import javax.ws.rs.core.MediaType;




/**
* This {@code SuccessFactorsTransporter} class is used to
* make a rest web service call to the SAP SuccessFactors exposed services.
Expand All @@ -50,14 +62,11 @@ public class SuccessFactorsTransporter {
private static final long CONNECTION_TIMEOUT = 300;
private static final long WAIT_TIME = 5;
private static final long MAX_NUMBER_OF_RETRY_ATTEMPTS = 5;

private final String username;
private final String password;
private SuccessFactorsConnectorConfig config;
private Response response;

public SuccessFactorsTransporter(String username, String password) {
this.username = username;
this.password = password;
public SuccessFactorsTransporter(SuccessFactorsConnectorConfig pluginConfig) {
this.config = pluginConfig;

}

Expand Down Expand Up @@ -152,7 +161,8 @@ public Response retrySapTransportCall(URL endpoint, String mediaType) throws IOE
* @throws TransportException any error while preparing the {@code OkHttpClient}
*/
private Response transport(URL endpoint, String mediaType) throws IOException, TransportException {
OkHttpClient enhancedOkHttpClient = getConfiguredClient().build();
OkHttpClient enhancedOkHttpClient =
buildConfiguredClient(config.getProxyUrl(), config.getProxyUsername(), config.getProxyPassword()).build();
Request req = buildRequest(endpoint, mediaType);

return enhancedOkHttpClient.newCall(req).execute();
Expand All @@ -177,7 +187,7 @@ private SuccessFactorsResponseContainer prepareResponseContainer(Response res) t
/**
* Prepares request for metadata and data calls.
*
* @param mediaType supported types 'application/json' & 'application/xml'
// * @param mediaType supported types 'application/json' & 'application/xml'
* @return Request
*/
private Request buildRequest(URL endpoint, String mediaType) {
Expand All @@ -189,6 +199,31 @@ private Request buildRequest(URL endpoint, String mediaType) {
.build();
}

private OkHttpClient.Builder buildConfiguredClient(String proxyUrl, String proxyUsername, String proxyPassword)
throws MalformedURLException, TransportException {
OkHttpClient.Builder builder = getConfiguredClient();

if (proxyUrl != null && !proxyUrl.isEmpty()) {
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(new URL(proxyUrl).getHost(),
new URL(proxyUrl).getPort()));
builder.proxy(proxy);

if (proxyUsername != null && !proxyUsername.isEmpty() && proxyPassword != null && !proxyPassword.isEmpty()) {
builder.proxyAuthenticator(new Authenticator() {
@Override
public Request authenticate(Route route, Response response) {
String credential = Credentials.basic(proxyUsername, proxyPassword);
return response.request().newBuilder()
.header("Proxy-Authorization", credential)
.build();
}
});
}
}

return builder;
}

/**
* Builds the {@code OkHttpClient.Builder} with following optimized configuration parameters as per the SAP Gateway
* recommendations.
Expand Down Expand Up @@ -218,9 +253,9 @@ private OkHttpClient.Builder getConfiguredClient() throws TransportException {
*/
private String getAuthenticationKey() {
return "Basic " + Base64.getEncoder()
.encodeToString(username
.encodeToString(config.getUsername()
.concat(":")
.concat(password)
.concat(config.getPassword())
.getBytes(StandardCharsets.UTF_8)
);
}
Expand Down
Loading

0 comments on commit 08482c0

Please sign in to comment.