Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,15 @@ If you already have an access token and endpoint (e.g. from a cookie), you can p

ForceApi api = new ForceApi(c,s);

### Instantiate with proxy

ForceApi api = new ForceApi(new ApiConfig()
.setProxyHost("127.0.0.1")
.setProxyPort(8080)
.setProxyUsername("proxy-user")
.setProxyPassword("proxy-password"));


## CRUD and Query Operations

### Get an SObject
Expand Down
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,8 @@
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>8</source>
<target>8</target>
<source>9</source>
<target>9</target>
</configuration>
</plugin>
<plugin>
Expand Down
65 changes: 62 additions & 3 deletions src/main/java/com/force/api/ApiConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.net.URI;
import java.net.URLDecoder;
import java.net.*;

public class ApiConfig {

Expand All @@ -16,6 +15,10 @@ public class ApiConfig {
String clientId;
String clientSecret;
String redirectURI;
String proxyHost;
Integer proxyPort;
String proxyUsername;
String proxyPassword;
SessionRefreshListener sessionRefreshListener;
ObjectMapper objectMapper;
int requestTimeout = 0; // in milliseconds, defaults to 0 which is no timeout (infinity)
Expand All @@ -35,7 +38,11 @@ public ApiConfig clone() {
.setClientSecret(clientSecret)
.setRedirectURI(redirectURI)
.setObjectMapper(objectMapper)
.setRequestTimeout(requestTimeout);
.setRequestTimeout(requestTimeout)
.setProxyHost(proxyHost)
.setProxyPort(proxyPort)
.setProxyUsername(proxyUsername)
.setProxyPassword(proxyPassword);
}

public ApiConfig setForceURL(String url) {
Expand Down Expand Up @@ -102,6 +109,37 @@ public ApiConfig setClientSecret(String value) {
clientSecret = value;
return this;
}

public ApiConfig setProxyHost(String value) {
proxyHost = value;
return this;
}

public ApiConfig setProxyPort(String value) {
try {
proxyPort = Integer.parseInt(value.trim());
}
catch(NullPointerException | NumberFormatException e){
proxyPort = null;
}
return this;
}

public ApiConfig setProxyPort(int value) {
proxyPort = value;
return this;
}

public ApiConfig setProxyUsername(String value) {
proxyUsername = value;
return this;
}

public ApiConfig setProxyPassword(String value) {
proxyPassword = value;
return this;
}

public ApiConfig setSessionRefreshListener(SessionRefreshListener value) {
sessionRefreshListener = value;
return this;
Expand Down Expand Up @@ -147,6 +185,27 @@ public String getRedirectURI() {
return redirectURI;
}

public ProxySettings getProxySettings() {
ApiConfig config = this;
Proxy proxy = null;
Authenticator authenticator = null;
if(proxyHost != null && proxyPort != null) {
proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort));
if(proxyUsername != null && proxyPassword != null) {
authenticator = new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
if (getRequestorType() == RequestorType.PROXY && config.proxyUsername != null && config.proxyPassword != null) {
return new PasswordAuthentication(config.proxyUsername, config.proxyPassword.toCharArray());
}
return null;
}
};
}
}
return new ProxySettings(proxy, authenticator);
}

public SessionRefreshListener getSessionRefreshListener() { return sessionRefreshListener; }

public ObjectMapper getObjectMapper() { return objectMapper; }
Expand Down
24 changes: 15 additions & 9 deletions src/main/java/com/force/api/Auth.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.net.*;
import java.util.Map;


Expand Down Expand Up @@ -40,7 +37,8 @@ static public final ApiSession oauthLoginPasswordFlow(ApiConfig c) {
.param("client_id",c.getClientId())
.param("client_secret", c.getClientSecret())
.param("username",c.getUsername())
.param("password",c.getPassword())
.param("password",c.getPassword()),
c.getProxySettings()
);
if(r.getResponseCode()!=200) {
throw new AuthException(r.getResponseCode(),"Auth.oauthLoginPasswordFlow failed: "+r.getString());
Expand Down Expand Up @@ -79,7 +77,12 @@ static public final ApiSession soaploginPasswordFlow(ApiConfig c) {
if(c.getPassword()==null) throw new IllegalStateException("password cannot be null");
try {
URL url = new URL(c.getLoginEndpoint()+"/services/Soap/u/33.0");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
Proxy proxy = c.getProxySettings().getProxy();
Authenticator authenticator = c.getProxySettings().getProxyAuthenticator();
HttpURLConnection conn = (HttpURLConnection) (proxy == null ? url.openConnection() : url.openConnection(proxy));
if(proxy != null && authenticator != null) {
conn.setAuthenticator(authenticator);
}
conn.setDoOutput(true);
conn.addRequestProperty("Content-Type", "text/xml");
conn.addRequestProperty("SOAPAction", "login");
Expand Down Expand Up @@ -161,7 +164,8 @@ static public final ApiSession completeOAuthWebServerFlow(AuthorizationResponse
.param("client_id",res.apiConfig.getClientId())
.param("client_secret", res.apiConfig.getClientSecret())
.param("redirect_uri",res.apiConfig.getRedirectURI())
.preEncodedParam("code",res.code)
.preEncodedParam("code",res.code),
res.apiConfig.getProxySettings()
);
if(r.getResponseCode()!=200) {
throw new AuthException(r.getResponseCode(),r.getString());
Expand Down Expand Up @@ -191,7 +195,8 @@ static public final ApiSession refreshOauthTokenFlow(ApiConfig config, String re
.param("grant_type","refresh_token")
.param("client_id",config.getClientId())
.param("client_secret", config.getClientSecret())
.param("refresh_token", refreshToken)
.param("refresh_token", refreshToken),
config.getProxySettings()
);
if(r.getResponseCode()!=200) {
throw new AuthException(r.getResponseCode(),r.getString());
Expand Down Expand Up @@ -222,7 +227,8 @@ static public void revokeToken(ApiConfig config, String token) {
Http.send(HttpRequest.formPost()
.header("Accept","*/*")
.url(config.getLoginEndpoint()+"/services/oauth2/revoke")
.param("token", token));
.param("token", token),
config.getProxySettings());
} catch(Throwable t) {
// Looks like revoke endpoint closes stream when trying to revoke
// an already revoked token. It doesn't return an error code. So
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/com/force/api/ForceApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,11 @@ public ForceApi(ApiSession session) {
}

public ForceApi(ApiConfig apiConfig) {
System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "");
config = apiConfig;
jsonMapper = config.getObjectMapper();
session = Auth.authenticate(apiConfig);
autoRenew = true;

}

public ApiSession getSession() {
Expand Down Expand Up @@ -496,7 +496,7 @@ private final String uriBaseOrRoot() {
private final HttpResponse apiRequest(HttpRequest req) {
req.setAuthorization("Bearer "+session.getAccessToken());
req.setRequestTimeout(this.config.getRequestTimeout());
HttpResponse res = Http.send(req);
HttpResponse res = Http.send(req, this.config.getProxySettings());
if(res.getResponseCode()==401) {
// Perform one attempt to auto renew session if possible
if (autoRenew) {
Expand All @@ -510,7 +510,7 @@ private final HttpResponse apiRequest(HttpRequest req) {
config.getSessionRefreshListener().sessionRefreshed(session);
}
req.setAuthorization("Bearer "+session.getAccessToken());
res = Http.send(req);
res = Http.send(req, this.config.getProxySettings());
}
}
// 304 is a special case when the "If-Modified-Since" header is used, it is not an error,
Expand Down
22 changes: 22 additions & 0 deletions src/main/java/com/force/api/ProxySettings.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.force.api;

import java.net.Authenticator;
import java.net.Proxy;

public class ProxySettings {
private final Proxy proxy;
private final Authenticator proxyAuthenticator;

ProxySettings(Proxy proxy, Authenticator proxyAuthenticator) {
this.proxy = proxy;
this.proxyAuthenticator = proxyAuthenticator;
}

public Proxy getProxy() {
return proxy;
}

public Authenticator getProxyAuthenticator() {
return proxyAuthenticator;
}
}
16 changes: 9 additions & 7 deletions src/main/java/com/force/api/http/Http.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.force.api.http;

import com.force.api.ProxySettings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -8,11 +9,7 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.*;


public class Http {
Expand Down Expand Up @@ -60,9 +57,14 @@ static final byte[] readResponse(InputStream stream) throws IOException {
return bout.toByteArray();
}

public static final HttpResponse send(HttpRequest req) {
public static final HttpResponse send(HttpRequest req, ProxySettings proxySettings) {
try {
HttpURLConnection conn = (HttpURLConnection) new URL(req.getUrl()).openConnection();
URL url = new URL(req.getUrl());
Proxy proxy = proxySettings.getProxy();
HttpURLConnection conn = (HttpURLConnection) (proxy == null ? url.openConnection() : url.openConnection(proxy));
if(proxy != null && proxySettings.getProxyAuthenticator() != null) {
conn.setAuthenticator(proxySettings.getProxyAuthenticator());
}
if(req.getRequestTimeout()>0){
conn.setConnectTimeout(req.getRequestTimeout());
conn.setReadTimeout(req.getRequestTimeout());
Expand Down