Our application is java based web application.
We cannot access third party api directly in this case https://api.twilio.com
This has to be done through a proxy.
Can anyone tell me how can I achieve it for TwilioRestClient?
You can use the .getHttpClient() method of TwilioRestClient and set your proxy parameters like this:
final TwilioRestClient client = new TwilioRestClient(ACCOUNT_SID, AUTH_TOKEN);
client.getHttpClient().getHostConfiguration().setProxy(PROXY_HOST, PROXY_PORT);
I know this is late for you, but I've been working around it because setting connection parameters directly to Apache's HttpClient is now deprecated. It is all done through builders and factories now. This is how I've done it with Apache httpcomponents 4.3.4:
HttpHost proxy = new HttpHost(PROXY_HOST, PROXY_PORT, "http");
DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(
new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT),
new UsernamePasswordCredentials(ACCOUNT_SID, ACCOUNT_TOKEN)
);
CloseableHttpClient httpClient = HttpClients.custom()
.setRoutePlanner(routePlanner)
.setDefaultCredentialsProvider(credentialsProvider)
.build();
TwilioRestClient client = new TwilioRestClient(ACCOUNT_SID, AUTH_TOKEN);
client.setHttpclient(httpClient);
//do your regular stuff with this client
Hope it helps.
If you are using above 7.0.0 or latest jar Twilio has provided its own HttpClient, follow these steps,
1) You need to create your customHttpProxy class that extends com.twilio.http.HttpClient
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.apache.http.Header;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.DefaultProxyRoutePlanner;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import com.google.common.collect.Lists;
import com.twilio.Twilio;
import com.twilio.exception.ApiException;
import com.twilio.http.HttpClient;
import com.twilio.http.HttpMethod;
import com.twilio.http.Request;
import com.twilio.http.Response;
import XXXX.XXX.twilio.util.TwilioUtil;
public class CustomNetworkClient extends HttpClient {
private static final int CONNECTION_TIMEOUT = 5000;
private static final int SOCKET_TIMEOUT = 5000;
private static final int CONNECTIONS_PER_ROUTE = 10;
private org.apache.http.client.HttpClient client;
private String twilioRequestId;
private Float twilioResponseDuration;
/**
* Create a new HTTP Client.
* #throws Exception
*/
public CustomNetworkClient() throws Exception {
this.invokeHttpProxy();
}
/**
* Make a request.
*
* #param request request to make
* #return Response of the HTTP request
*/
public Response makeRequest(final Request request) {
twilioResponseDuration = null;
twilioRequestId = null;
RequestBuilder builder = RequestBuilder.create(request.getMethod().toString())
.setUri(request.constructURL().toString())
.setVersion(HttpVersion.HTTP_1_1)
.setCharset(StandardCharsets.UTF_8);
if (request.requiresAuthentication()) {
builder.addHeader(HttpHeaders.AUTHORIZATION, request.getAuthString());
}
HttpMethod method = request.getMethod();
if (method == HttpMethod.POST) {
builder.addHeader(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded");
for (Map.Entry<String, List<String>> entry : request.getPostParams().entrySet()) {
for (String value : entry.getValue()) {
builder.addParameter(entry.getKey(), value);
}
}
}
try {
HttpResponse response = client.execute(builder.build());
if (response.containsHeader("Twilio-Request-Id"))
twilioRequestId = response.getFirstHeader("Twilio-Request-Id").getValue();
if (response.containsHeader("Twilio-Request-Duration"))
twilioResponseDuration = new Float(response.getFirstHeader("Twilio-Request-Duration").getValue());
return new Response(
response.getEntity() == null ? null : response.getEntity().getContent(),
response.getStatusLine().getStatusCode()
);
} catch (IOException e) {
throw new ApiException(e.getMessage());
}
}
public String getTwilioRequestId() {
return twilioRequestId;
}
public Float getTwilioResponseDuration() {
return twilioResponseDuration;
}
public void invokeHttpProxy()throws Exception {
HttpHost proxy = new HttpHost("YOUR_PROXY_HOST", YOUR_PROXY_PORT, "http");
DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);
//Set up Twilio user credentials
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope("api.twilio.com", 443),
new UsernamePasswordCredentials(TwilioUtil.ACCOUNT_SID, TwilioUtil.AUTH_TOKEN));
RequestConfig config = RequestConfig.custom()
.setConnectTimeout(CONNECTION_TIMEOUT)
.setSocketTimeout(SOCKET_TIMEOUT)
.build();
Collection<Header> headers = Lists.<Header>newArrayList(
new BasicHeader("X-Twilio-Client", "java-" + Twilio.VERSION),
new BasicHeader(HttpHeaders.USER_AGENT, "twilio-java/" + Twilio.VERSION + " (" + Twilio.JAVA_VERSION + ")"),
new BasicHeader(HttpHeaders.ACCEPT, "application/json"),
new BasicHeader(HttpHeaders.ACCEPT_ENCODING, "utf-8")
);
client = HttpClientBuilder.create().setRoutePlanner(routePlanner)
.setDefaultCredentialsProvider(credsProvider)
.setConnectionManager(new PoolingHttpClientConnectionManager())
.setDefaultRequestConfig(config)
.setDefaultHeaders(headers)
.setMaxConnPerRoute(CONNECTIONS_PER_ROUTE)
.build();
}
}
2) Inject the custom class into Twilio and TwilioRestClient respectively.
CustomNetworkClient newHttpClient = new CustomNetworkClient();
Twilio.init(TwilioUtil.ACCOUNT_SID, TwilioUtil.AUTH_TOKEN);
TwilioRestClient client = new TwilioRestClient.Builder(TwilioUtil.ACCOUNT_SID, TwilioUtil.AUTH_TOKEN).httpClient(newHttpClient)
.build();`enter code here`
Twilio.setRestClient(client);
Hope this is helpful to your guys.
Thanks a lot for the preceding. I write a much elegant class than ustomNetworkClient
import com.twilio.http.NetworkHttpClient;
import lombok.RequiredArgsConstructor;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
public class ProxyAuthenticateHttpClient extends NetworkHttpClient {
private ProxyAuthenticateHttpClient(HttpClientBuilder clientBuilder) {
super(clientBuilder);
}
#RequiredArgsConstructor
public static class Builder {
public ProxyAuthenticateHttpClient build() {
HttpClientBuilder clientBuilder = HttpClientBuilder.create();
clientBuilder.useSystemProperties();
RequestConfig config = RequestConfig.custom()
.setConnectTimeout(CONNECTION_TIMEOUT)
.setSocketTimeout(SOCKET_TIMEOUT)
.build();
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(new AuthScope(proxyHost, proxyPort),
new UsernamePasswordCredentials(proxyUser, proxyPassword));
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
connectionManager.setDefaultMaxPerRoute(10);
connectionManager.setMaxTotal(10*2);
clientBuilder
.setConnectionManager(connectionManager)
.setDefaultCredentialsProvider(credsProvider)
.setDefaultRequestConfig(config);
return new ProxyAuthenticateHttpClient(clientBuilder);
}
private final String proxyHost;
private final int proxyPort;
private final String proxyUser;
private final String proxyPassword;
private static final int CONNECTION_TIMEOUT = 10000;
private static final int SOCKET_TIMEOUT = 30500;
}
}
Then use the following code to init Twilio and everything is OK
Twilio.init(username, password);
TwilioRestClient.Builder builder = new TwilioRestClient.Builder(username, password);
builder.httpClient(new ProxyAuthenticateHttpClient.Builder(proxyUser, proxyPort, proxyUser, proxyPassword).build());
Twilio.setRestClient(builder.build());
Ful Source code = https://github.com/mjg123/Twilio-custom-http-clients/blob/main/src/main/java/com/twilio/helperv8/RestClientProxy.java
Twilio's api lives on the internet, and many folks on corporate networks will therefore need to configure an http proxy to access it. Again this is possible with a custom twiliorestclient, although in this case we'll need to write some code of our own. There are a few layers to this, so let's unpack them:
a twiliorestclient builder can take a custom instance of com. Twilio. Http. Httpclient. (this would be a good place to inject a mock for testing your calls to the twilio api)
the default implementation of twilio's httpclient is called networkhttpclient.
Networkhttpclient can be initialised with an apache httpcomponents httpclientbuilder.
Httpclientbuilder can be configured to use a proxy.
To create an httpclient instance, this code is sufficient:
private static HttpClient createProxiedHttpClient(String proxyHost, int proxyPort) {
// you can also configure things like caching, custom HTTPS certs,
// timeouts and connection pool sizes here.
// See: https://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/impl/client/HttpClientBuilder.html
HttpClientBuilder apacheClientBuilder = HttpClientBuilder.create()
.setProxy(new HttpHost(proxyHost, proxyPort));
return new NetworkHttpClient(apacheClientBuilder);
}
private static final String PROXY_HOST = "localhost";
private static final int PROXY_PORT = 8888;
public static void main(String[] args) {
HttpClient proxiedHttpClient = createProxiedHttpClient(PROXY_HOST, PROXY_PORT);
TwilioRestClient proxiedTwilioClient = new TwilioRestClient.Builder(
PROJECT_CAKE_ACCOUNT_SID,
PROJECT_CAKE_AUTH_TOKEN)
.httpClient(proxiedHttpClient)
.build();
Message.creator(
TO_PHONE_NUMBER,
PROJECT_CAKE_PHONE_NUMBER,
"Cake, or Pie?")
.create(proxiedTwilioClient);
}
Related
I am trying to make a SOAP activity with digest authorization. When i am trying to connect to the test service, I get the below error:
Exception in thread "main" org.apache.http.conn.HttpHostConnectException: Connect to httpbin.org:135 [httpbin.org/34.231.30.52, httpbin.org/54.166.163.67, httpbin.org/54.91.118.50, httpbin.org/34.199.75.4] failed: Connection timed out: connect
at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:159)
at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:359)
at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:381)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:237)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:185)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:111)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:72)
at SOAPClientApache.run(SOAPClientApache.java:94)
at Main.main(Main.java:4)
Caused by: java.net.ConnectException: Connection timed out: connect
at java.base/java.net.PlainSocketImpl.connect0(Native Method)
at java.base/java.net.PlainSocketImpl.socketConnect(PlainSocketImpl.java:101)
at java.base/java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:399)
at java.base/java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:242)
at java.base/java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:224)
at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.base/java.net.Socket.connect(Socket.java:609)
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:339)
at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:142)
... 10 more
What I did for the solution:
Changed the port number
Changed the URL
Changed the PC on which the project was launched...Nothing helped me :(
I would be grateful for any help. Code:
SOAPClientApache
import java.io.Serializable;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.commons.io.IOUtils;
import org.apache.http.*;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.*;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.auth.DigestScheme;
import org.apache.http.impl.client.*;
import org.apache.http.ssl.SSLContextBuilder;
import org.testng.Assert;
import javax.net.ssl.*;
public class SOAPClientApache {
private static final String URL = "http://httpbin.org/digest-auth/auth/user/passwd";
//private static final String URL = "https://www.google.com/";
private static final String PASSWORD = "";
private static final String USER = "";
public void run() throws Exception {
HttpGet httpget = new HttpGet(URL);
HttpHost target
= new HttpHost(httpget.getURI().getHost(), 135, "https");
CredentialsProvider credsProvider = new BasicCredentialsProvider();
UsernamePasswordCredentials credentials
= new UsernamePasswordCredentials(USER, PASSWORD);
credsProvider.setCredentials(
new AuthScope(target.getHostName(), target.getPort()),
credentials);
CookieStore cookieStore = new BasicCookieStore();
//Start fix SSL (убиваем проверку сертификатов)
SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(null, new TrustSelfSignedStrategy() {
#Override
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
return true;
}
});
SSLConnectionSocketFactory sslSF = new SSLConnectionSocketFactory(builder.build(),
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
//End fix SSL
//SSL solution (ДО обхода проверки SSL)
/*CloseableHttpClient httpclient
= HttpClients.custom().setDefaultCookieStore(cookieStore)
.setDefaultCredentialsProvider(credsProvider).build();*/
CloseableHttpClient httpclient
= HttpClients.custom().setDefaultCookieStore(cookieStore)
.setDefaultCredentialsProvider(credsProvider).setSSLSocketFactory(sslSF).build();
try {
DigestScheme digestAuth = new DigestScheme();
digestAuth.overrideParamter("qop", "auth");
digestAuth.overrideParamter("nc", "0");
digestAuth.overrideParamter("cnonce", DigestScheme.createCnonce());
AuthCache authCache = new BasicAuthCache();
authCache.put(target, digestAuth);
HttpClientContext localContext = HttpClientContext.create();
localContext.setAuthCache(authCache);
CloseableHttpResponse response;
response = httpclient.execute(target, httpget, localContext);
Map<String, String> wwwAuth = Arrays
.stream(response.getHeaders("WWW-Authenticate")[0]
.getElements())
.collect(Collectors.toMap(HeaderElement::getName,
HeaderElement::getValue));
// the first call ALWAYS fails with a 401
Assert.assertEquals(response.getStatusLine().getStatusCode(), 401);
digestAuth.overrideParamter("opaque", wwwAuth.get("opaque"));
digestAuth.overrideParamter("nonce", wwwAuth.get("nonce"));
digestAuth.overrideParamter("realm", wwwAuth.get("Digest realm"));
Header authenticate = digestAuth.authenticate(credentials, httpget,
localContext);
httpget.addHeader(authenticate);
response = httpclient.execute(target, httpget, localContext);
// the 2nd call is the real deal
Assert.assertEquals(response.getStatusLine().getStatusCode(), 200);
System.out.println(IOUtils
.toString(response.getEntity().getContent(), "utf-8"));
} finally {
httpclient.close();
}
}
}
Main
public class Main {
public static void main(String[] args) throws Exception {
SOAPClientApache soapClientApache = new SOAPClientApache();
soapClientApache.run();
}
}
The solution turned out to be quite simple.
I have set the correct port for me
HttpHost target = new HttpHost(httpget.getURI().getHost(), 443, "https");
I also disabled my firewall.
I am setting up a java Twilio connection using the example Twilio java-sdk from the api examples here.
The only difference is I need to run my Twilio connection through a web-proxy with authentication.
There are other questions about connecting to Twilio through a web-proxy but no accepted answers. For example this, based on that answer I have tried implementing a solution like this:
import com.twilio.sdk.TwilioRestClient;
import com.twilio.sdk.TwilioRestException;
import com.twilio.sdk.resource.factory.MessageFactory;
import com.twilio.sdk.resource.instance.Message;
import org.apache.http.HttpHost;
import org.apache.http.NameValuePair;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.DefaultProxyRoutePlanner;
import org.apache.http.message.BasicNameValuePair;
import java.util.ArrayList;
import java.util.List;
public class Example {
// Find your Account Sid and Token at twilio.com/console
public static final String ACCOUNT_SID = "asdfasdfasdfdasf";
public static final String AUTH_TOKEN = "asdfasdfasdfasdf";
public static final String PROXY_ADDRESS = "1.2.3.4";
public static final int PROXY_PORT = 80;
public static final String PROXY_USER = "user";
public static final String PROXY_PASSWORD = "password";
public static void main(String[] args) {
//Set up Proxy host
HttpHost proxy = new HttpHost(PROXY_ADDRESS, PROXY_PORT);
DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);
//Set up Proxy user credentials
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope(PROXY_ADDRESS, PROXY_PORT),
new UsernamePasswordCredentials(PROXY_USER, PROXY_PASSWORD));
//Set up HttpClient with proxy and credentials
CloseableHttpClient httpClient = HttpClients.custom()
.setRoutePlanner(routePlanner)
.setDefaultCredentialsProvider(credsProvider)
.build();
TwilioRestClient client = new TwilioRestClient(ACCOUNT_SID, AUTH_TOKEN);
client.setHttpClient(httpClient);
// Build a filter for the MessageList
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("Body", "Hello from Java"));
params.add(new BasicNameValuePair("To", "+12345678901"));
params.add(new BasicNameValuePair("From", "+12345678901"));
MessageFactory messageFactory = client.getAccount().getMessageFactory();
try {
Message message;
message = messageFactory.create(params);
System.out.println(message.getSid());
} catch (TwilioRestException e) {
System.out.println(e.getErrorCode());
System.out.println(e.getErrorMessage());
e.printStackTrace();
}
}
}
It seems to be making it through the proxy with this and reaching the Twilio API but it returns a 20003 error every time. (permission denied)
I suspect that the http-client web proxy authentication is overwriting the twilio account SID and auth token but I am not sure, or if there is a way around this.
I have triple checked my own account SID and auth token and also tried using the "testing" SID and auth token that Twilio provides for the account also but I get the same result.
Any advice for running the Twilio java-sdk through a web proxy?
I am using apache http-client library 4.5.2
Resolved... just needed to add another set of credentials that were scoped to api.twilio.com after the proxy credentials:
//Set up Proxy user credentials
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope(PROXY_ADDRESS, PROXY_PORT),
new UsernamePasswordCredentials(PROXY_USER, PROXY_PASSWORD));
//Set up Twilio user credentials
credsProvider.setCredentials(
new AuthScope("api.twilio.com", 443),
new UsernamePasswordCredentials(ACCOUNT_SID, AUTH_TOKEN));
I'll leave this here for posterity because there has been several questions about this but no accepted answers.
I am using Twilio Java 3.4.5 and I am setting the proxy this way as all my outbound requests to Twilio has to go thru my proxy server.
TwilioRestClient client = new TwilioRestClient(twilioSid, twilioAuthToken);
client.setHttpclient(getProxyClient());
private HttpClient getProxyClient() {
HttpHost proxy = new HttpHost(proxyHost, proxyPort, "http");
DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(
new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT),
new UsernamePasswordCredentials(twilioSid, twilioAuthToken)
);
CloseableHttpClient httpClient = HttpClients.custom()
.setRoutePlanner(routePlanner)
.setDefaultCredentialsProvider(credentialsProvider)
.build();
return httpClient;
}
I realized that 3.4.5 was more than 1.5 years old and I tried upgrading one of the latest versions (say 5.0 or higher).
I do not see the method .setHttpClient() in the latest versions of Twilio library.
How do I set proxy when I use 5.0 or above?
I do not see any documentation for it...
Please ignore this as in 3.4.5 the method is called setHttpclient() (c in lowercase) whereas with latest library versions it is setHttpClient()
If you are using above 7.0.0 or latest jar Twilio has provided its own HttpClient
Follow the steps:
1) You need to create your customHttpProxy class that extends com.twilio.http.HttpClient
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.apache.http.Header;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.DefaultProxyRoutePlanner;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import com.google.common.collect.Lists;
import com.twilio.Twilio;
import com.twilio.exception.ApiException;
import com.twilio.http.HttpClient;
import com.twilio.http.HttpMethod;
import com.twilio.http.Request;
import com.twilio.http.Response;
import XXXX.XXX.twilio.util.TwilioUtil;
public class CustomNetworkClient extends HttpClient {
private static final int CONNECTION_TIMEOUT = 5000;
private static final int SOCKET_TIMEOUT = 5000;
private static final int CONNECTIONS_PER_ROUTE = 10;
private org.apache.http.client.HttpClient client;
private String twilioRequestId;
private Float twilioResponseDuration;
/**
* Create a new HTTP Client.
* #throws Exception
*/
public CustomNetworkClient() throws Exception {
this.invokeHttpProxy();
}
/**
* Make a request.
*
* #param request request to make
* #return Response of the HTTP request
*/
public Response makeRequest(final Request request) {
twilioResponseDuration = null;
twilioRequestId = null;
RequestBuilder builder = RequestBuilder.create(request.getMethod().toString())
.setUri(request.constructURL().toString())
.setVersion(HttpVersion.HTTP_1_1)
.setCharset(StandardCharsets.UTF_8);
if (request.requiresAuthentication()) {
builder.addHeader(HttpHeaders.AUTHORIZATION, request.getAuthString());
}
HttpMethod method = request.getMethod();
if (method == HttpMethod.POST) {
builder.addHeader(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded");
for (Map.Entry<String, List<String>> entry : request.getPostParams().entrySet()) {
for (String value : entry.getValue()) {
builder.addParameter(entry.getKey(), value);
}
}
}
try {
HttpResponse response = client.execute(builder.build());
if (response.containsHeader("Twilio-Request-Id"))
twilioRequestId = response.getFirstHeader("Twilio-Request-Id").getValue();
if (response.containsHeader("Twilio-Request-Duration"))
twilioResponseDuration = new Float(response.getFirstHeader("Twilio-Request-Duration").getValue());
return new Response(
response.getEntity() == null ? null : response.getEntity().getContent(),
response.getStatusLine().getStatusCode()
);
} catch (IOException e) {
throw new ApiException(e.getMessage());
}
}
public String getTwilioRequestId() {
return twilioRequestId;
}
public Float getTwilioResponseDuration() {
return twilioResponseDuration;
}
public void invokeHttpProxy()throws Exception {
HttpHost proxy = new HttpHost("YOUR_PROXY_HOST", YOUR_PROXY_PORT, "http");
DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);
//Set up Twilio user credentials
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope("api.twilio.com", 443),
new UsernamePasswordCredentials(TwilioUtil.ACCOUNT_SID, TwilioUtil.AUTH_TOKEN));
RequestConfig config = RequestConfig.custom()
.setConnectTimeout(CONNECTION_TIMEOUT)
.setSocketTimeout(SOCKET_TIMEOUT)
.build();
Collection<Header> headers = Lists.<Header>newArrayList(
new BasicHeader("X-Twilio-Client", "java-" + Twilio.VERSION),
new BasicHeader(HttpHeaders.USER_AGENT, "twilio-java/" + Twilio.VERSION + " (" + Twilio.JAVA_VERSION + ")"),
new BasicHeader(HttpHeaders.ACCEPT, "application/json"),
new BasicHeader(HttpHeaders.ACCEPT_ENCODING, "utf-8")
);
client = HttpClientBuilder.create().setRoutePlanner(routePlanner)
.setDefaultCredentialsProvider(credsProvider)
.setConnectionManager(new PoolingHttpClientConnectionManager())
.setDefaultRequestConfig(config)
.setDefaultHeaders(headers)
.setMaxConnPerRoute(CONNECTIONS_PER_ROUTE)
.build();
}
}
2) Inject the custom class into Twilio and TwilioRestClient respectively.
CustomNetworkClient newHttpClient = new CustomNetworkClient();
Twilio.init(TwilioUtil.ACCOUNT_SID, TwilioUtil.AUTH_TOKEN);
TwilioRestClient client = new TwilioRestClient.Builder(TwilioUtil.ACCOUNT_SID, TwilioUtil.AUTH_TOKEN).httpClient(newHttpClient)
.build();
Twilio.setRestClient(client);
Hope this is helpful to your guys
In C# code we are using network authentication:
req = HttpWebRequest.Create(Url)
req.Method = "POST"
req.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip, deflate")
req.Credentials = New NetworkCredential(Username, Password)
We need to implement same in Java. I have tried folowing two approach but it is not working:
httppost.setHeader("Authorization", "Basic " + "username:password");
Authenticator.setDefault(new PaswordAuthentication());
but both did not work.
Any lead will be highly appreciated.
Although the following link answers the question it does not show a full solution using HttpClientBuilder. Here is the full sample that gets the index file from an IIS server requiring Windows Authentication.
package test;
import java.util.*;
import org.apache.http.*;
import org.apache.http.auth.*;
import org.apache.http.client.*;
import org.apache.http.client.config.*;
import org.apache.http.client.methods.*;
import org.apache.http.impl.client.*;
import org.apache.http.util.*;
public class Test
{
public static void main(String[] args)
{
try
{
RequestConfig requestConfig = RequestConfig.custom()
.setTargetPreferredAuthSchemes(Arrays.asList(AuthSchemes.NTLM))
.setProxyPreferredAuthSchemes(Arrays.asList(AuthSchemes.BASIC))
.build();
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY,
new NTCredentials("USERNAME", "PASSWORD", "HOSTNAME", "DOMAIN"));
HttpClient httpclient = HttpClients.custom()
.setDefaultCredentialsProvider(credentialsProvider)
.setDefaultRequestConfig(requestConfig)
.build();
HttpHost target = new HttpHost("localhost", 80, "http");
HttpGet httpget = new HttpGet("/");
HttpResponse r = httpclient.execute(target, httpget);
HttpEntity e = r.getEntity();
String responseString = EntityUtils.toString(e, "UTF-8");
System.out.println(responseString);
}
catch (Exception ex)
{
System.out.println(ex.getMessage());
}
}
}
Have you tried org.apache.commons.httpclient.NTCredentials?
Here's a link to some samples.
All:
I need to be able to POST a job to Jenkins using the Jenkins REST API but have not been able to get past authentication. I have been attempting to do this for a few days now and have researched answers on both this site and on the Jenkins site. I have been trying to use the Apache HttpClient with no success (even with preemptive validation). I keep getting error code 403 - forbidden. Has anyone been able to do this successfully? Here is the code that I am working with:
package stackoverflow.question;
import gsafame.sample;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.NameValuePair;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthCache;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.BasicAuthCache;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
public class PreEmptiveAuth {
final Logger log = Logger.getLogger(sample.class.getCanonicalName());
private JobData jd;
private CredentialsProvider credpro;
private AuthScope as;
private UsernamePasswordCredentials upc;
private String url;
public PreEmptiveAuth(JobData jd) {
this.jd = jd;
credpro = new BasicCredentialsProvider();
as = new AuthScope(jd.getServer(), 443);
upc = new UsernamePasswordCredentials(jd.getUsername(), jd.getPassword());
credpro.setCredentials(as, upc);
url = String.format("%s:8080/jenkins/job/%s/buildWithParameters", jd.getServer(), jd.getJob());
}
public void runTagJob() throws ClientProtocolException, IOException {
log.entering(this.getClass().getCanonicalName(), "runTagJob");
log.info("Entering runTagJob");
CloseableHttpClient httpclient = HttpClients.custom()
.setDefaultCredentialsProvider(credpro).build();
HttpPost httpPost = new HttpPost(url);
List <NameValuePair> nvps = new ArrayList <NameValuePair>();
nvps.add(new BasicNameValuePair("username", jd.getUsername()));
nvps.add(new BasicNameValuePair("password", jd.getPassword()));
nvps.add(new BasicNameValuePair("apiToken", jd.getToken()));
httpPost.setEntity(new UrlEncodedFormEntity(nvps));
CloseableHttpResponse response2 = httpclient.execute(httpPost);
try {
System.out.println(response2.getStatusLine());
HttpEntity entity2 = response2.getEntity();
// do something useful with the response body
// and ensure it is fully consumed
EntityUtils.consume(entity2);
} finally {
response2.close();
}
log.info("Exiting runTagJob");
log.exiting(this.getClass().getCanonicalName(), "runTagJob");
}
public void runPreTagJob() throws ClientProtocolException, IOException {
log.entering(this.getClass().getCanonicalName(), "runPreTagJob");
log.info("Entering runPreTagJob");
HttpHost targetHost = new HttpHost(jd.getServer(), 8080, "http");
CloseableHttpClient httpclient = HttpClients.custom()
.setDefaultCredentialsProvider(credpro).build();
try {
// Create AuthCache instance
AuthCache authCache = new BasicAuthCache();
// Generate BASIC scheme object and add it to the local auth cache
BasicScheme basicAuth = new BasicScheme();
authCache.put(targetHost, basicAuth);
// Add AuthCache to the execution context
HttpClientContext localContext = HttpClientContext.create();
localContext.setAuthCache(authCache);
HttpPost httpPost = new HttpPost(url);
List <NameValuePair> nvps = new ArrayList <NameValuePair>();
nvps.add(new BasicNameValuePair("username", jd.getUsername()));
nvps.add(new BasicNameValuePair("password", jd.getPassword()));
nvps.add(new BasicNameValuePair("apiToken", jd.getToken()));
httpPost.setEntity(new UrlEncodedFormEntity(nvps));
CloseableHttpResponse response2 = httpclient.execute(targetHost, httpPost, localContext);
try {
System.out.println(response2.getStatusLine());
HttpEntity entity2 = response2.getEntity();
// do something useful with the response body
// and ensure it is fully consumed
EntityUtils.consume(entity2);
} finally {
response2.close();
}
} finally {
httpclient.close();
}
log.info("Exiting runPreTagJob");
log.exiting(this.getClass().getCanonicalName(), "runPreTagJob");
}
}
The JobData object that gets passed into this class contains information like username, password, server, and job information. I hope this helps!
After researching on several sites, I managed to piece enough information together to come up with a solution. I am using older HTTP authentication code that is in some instances deprecated - but it works when nothing else would. If anyone has a better solution, I would be interested in seeing it. Anyway, here it is:
Main Class:
package stackoverflow.answer;
import java.util.List;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
public class sample {
public static void main(String[] args) throws Exception {
final Logger log = Logger.getLogger(sample.class.getCanonicalName());
JobData jd = new JobData();
Scanner input = new Scanner(System.in);
try {
System.out.print("What is your user name? ");
jd.setUsername(input.next());
System.out.print("What is your password? ");
jd.setPassword(input.next());
} catch (Exception e) {
log.log(Level.SEVERE, "The system encountered an exception while attempting to login");
} finally {
input.close();
}
jd.setJob("TestREST");
jd.setServer("http://YOUR-SERVER");
jd.setPort("YOUR-PORT");
// set the parameters
List<NameValuePair> parameters = jd.getParameters();
parameters.add(new BasicNameValuePair("SONAR-TARGET", "true"));
parameters.add(new BasicNameValuePair("RELEASE", "1311.1.1"));
parameters.add(new BasicNameValuePair("REVISION", "HEAD"));
// run the job
JenkinsPoster jp = new JenkinsPoster(jd);
log.info("executing postJenkinsJob");
jp.postJenkinsJob();
log.info("executed postJenkinsJob");
}
}
The JobData class (holds information about the job you need to run)
package stackoverflow.answer;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.NameValuePair;
public class JobData {
private String username;
private String password;
private String token;
private String server;
private String port;
private String job;
private List<NameValuePair> parameters;
public JobData() {
parameters = new ArrayList<NameValuePair>();
}
public String getUsername() {return username;}
public void setUsername(String username) {this.username = username;}
public String getPassword() {return password;}
public void setPassword(String password) {this.password = password;}
public String getToken() {return token;}
public void setToken(String token) {this.token = token;}
public String getServer() {return server;}
public void setServer(String server) {this.server = server;}
public String getPort() {return port;}
public void setPort(String port) {this.port = port;}
public String getJob() {return job;}
public void setJob(String job) {this.job = job;}
public List<NameValuePair> getParameters() {return parameters;}
}
The JenkinsPoster class (contains the business logic to connect to Jenkins and POST the job)
package stackoverflow.answer;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.logging.Logger;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.util.EntityUtils;
public class JenkinsPoster {
final Logger log = Logger.getLogger(getClass().getCanonicalName());
private JobData jd;
public JenkinsPoster(JobData jobData) {
this.jd = jobData;
}
#SuppressWarnings("deprecation")
public void postJenkinsJob() throws UnsupportedEncodingException {
log.entering(getClass().getCanonicalName(), "JenkinsPoster");
// Jenkins url
String jenkinsUrl = String.format("%s:%s/jenkins", jd.getServer(), jd.getPort());
log.info("url = " + jenkinsUrl);
// Create your httpclient
DefaultHttpClient client = new DefaultHttpClient();
// Then provide the right credentials
client.getCredentialsProvider().setCredentials(new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT),
new UsernamePasswordCredentials(jd.getUsername(), jd.getPassword()));
// Generate BASIC scheme object and stick it to the execution context
BasicScheme basicAuth = new BasicScheme();
BasicHttpContext context = new BasicHttpContext();
context.setAttribute("preemptive-auth", basicAuth);
// Add as the first (because of the zero) request interceptor
// It will first intercept the request and preemptively initialize the authentication scheme if there is not
client.addRequestInterceptor(new PreemptiveAuth(), 0);
// Post the request to start the build
List<NameValuePair> parameters = jd.getParameters();
UrlEncodedFormEntity uefe = null;
String buildUrl = "";
if (parameters.isEmpty()) {
buildUrl = jenkinsUrl + "/job/" + jd.getJob() + "/build";
}
else {
buildUrl = jenkinsUrl + "/job/" + jd.getJob() + "/buildWithParameters";
uefe = new UrlEncodedFormEntity(parameters);
}
HttpPost post = new HttpPost(buildUrl);
post.setHeader("User-Agent", "Mozilla/5.0");
if (uefe != null) {
post.setEntity(uefe);
}
try {
// Execute your request with the given context
HttpResponse response = client.execute(post, context);
HttpEntity entity = response.getEntity();
log.info(EntityUtils.toString(entity));
EntityUtils.consume(entity);
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally {
client.close();
}
log.exiting(getClass().getCanonicalName(), "JenkinsPoster");
}
}
... and finally, the PreemptiveAuth class that the previous class uses to preemptively login to Jenkins.
package stackoverflow.answer;
import java.io.IOException;
import org.apache.http.HttpException;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.AuthState;
import org.apache.http.auth.Credentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HttpContext;
public class PreemptiveAuth implements HttpRequestInterceptor {
public void process(HttpRequest request, HttpContext context)
throws HttpException, IOException {
// Get the AuthState
AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE);
// If no auth scheme available yet, try to initialize it preemptively
if (authState.getAuthScheme() == null) {
AuthScheme authScheme = (AuthScheme) context.getAttribute("preemptive-auth");
CredentialsProvider credsProvider = (CredentialsProvider) context
.getAttribute(ClientContext.CREDS_PROVIDER);
HttpHost targetHost = (HttpHost) context.getAttribute(ExecutionContext.HTTP_TARGET_HOST);
if (authScheme != null) {
Credentials creds = credsProvider.getCredentials(new AuthScope(targetHost.getHostName(), targetHost
.getPort()));
if (creds == null) {
throw new HttpException("No credentials for preemptive authentication");
}
authState.setAuthScheme(authScheme);
authState.setCredentials(creds);
}
}
}
}
Documentation on handling Jenkins' REST API authentication can be found here:
https://wiki.jenkins-ci.org/display/JENKINS/Authenticating+scripted+clients