How to POST an authenticated Jenkins job using Java - java

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

Related

JavaFX - Making a post request using org.apache.httpcomponents fails

When making a post request to my backend, I get the following error. I can't really find a fix online and am very new to Java.
Here is the error:
Caused by: java.lang.ClassNotFoundException: org.apache.http.concurrent.Cancellable
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
... 59 more
Code
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
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;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.http.HttpHeaders;
import java.util.ArrayList;
import java.util.List;
public class APIBridge {
private final CloseableHttpClient httpClient = HttpClients.createDefault();
public String url = "http://localhost:9004/index.php";
public static void Register(String username, String password) throws UnsupportedEncodingException {
String url = "http://localhost:9004/index.php";
HttpPost post = new HttpPost(url);
// Add request parameter, form parameters
List<NameValuePair> urlParameters = new ArrayList<>();
urlParameters.add(new BasicNameValuePair("username", username));
urlParameters.add(new BasicNameValuePair("password", password));
urlParameters.add(new BasicNameValuePair("Register", "true"));
post.setEntity(new UrlEncodedFormEntity(urlParameters));
try (CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = httpClient.execute(post)) {
System.out.println(EntityUtils.toString(response.getEntity()));
} catch (ClientProtocolException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private void close() throws IOException {
httpClient.close();
}
private void sendGet() throws Exception {
HttpGet request = new HttpGet("https://www.google.com/search?q=mkyong");
// Add request headers
request.addHeader("custom-key", "mkyong");
//request.addHeader(, "Googlebot");
try (CloseableHttpResponse response = httpClient.execute(request)) {
// Get HttpResponse Status
System.out.println(response.getStatusLine().toString());
HttpEntity entity = response.getEntity();
Header headers = entity.getContentType();
System.out.println(headers);
if (entity != null) {
// Return it as a String
String result = EntityUtils.toString(entity);
System.out.println(result);
}
}
}
IMO, it is easier to use the HTTP client in the JDK, so I have provided an answer demonstrating this alternate approach.
The Apache HTTP libraries were never targeted at somebody who is "new to Java". If you use them, make sure you use the correct versions of all the libraries and matching documentation as the library has gone through multiple incompatible API changes over years of library upgrades.
From your question, your module-info.java may be wrong or may need to be deleted. But your issue could also be caused by an environment setup or dependency version issue.
Basically, the class isn’t on the class or module path. Or it is on a path, but it is not accessible. The reason for that is not discernable from your question.
Example JavaFXApp using JDK HTTP Client
Makes a post request, gets the result as text and places the text in a TextArea.
module-info.java
module com.example.httpapp {
requires javafx.controls;
requires java.net.http;
exports com.example.httpapp;
}
src/main/java/com/example/httpapp/HttpApp.java
package com.example.httpapp;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.stage.Stage;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class HttpApp extends Application {
#Override
public void start(Stage stage) throws IOException, URISyntaxException, InterruptedException {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI("http://jsonplaceholder.typicode.com/posts"))
.POST(HttpRequest.BodyPublishers.ofString("Sample Post Request"))
.build();
HttpResponse<String> response = client.send(
request,
HttpResponse.BodyHandlers.ofString()
);
String responseBody = response.body();
TextArea textArea = new TextArea(responseBody);
textArea.setStyle("-fx-font-family: monospace;");
stage.setScene(new Scene(textArea));
stage.show();
}
public static void main(String[] args) {
launch();
}
}
Authentication
Outside of a local test app, you should not send unencrypted authentication data over a network connection as you have in your question code.
If you also need authentication, it is best to communicate over HTTPS. Then you can securely use basic or digest authentication, or HTTPS mutual authentication, or encode the authentication information in the post body.
Examples for basic authentication using the Java HTTP client are at:
Baeldung: Java HttpClient Basic Authentication

Apache HTTPClient DigestAuth authorization doesn't work

At the first access to the server, my authorization is successful (although this is not correct). I don’t understand why digest authorization in this code occurs so early.
I'm using the following solution:
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.*;
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 = "https://httpbin.org/digest-auth/auth/user/passwd";
private static final String PASSWORD = "passwd"; //passwd
private static final String USER = "user"; //user
public void run() throws Exception {
HttpGet httpget = new HttpGet(URL);
HttpHost target = new HttpHost(httpget.getURI().getHost(), 443, "https");
CredentialsProvider credsProvider = new BasicCredentialsProvider();
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(USER, PASSWORD);
credsProvider.setCredentials(
new AuthScope(target.getHostName(), target.getPort()),
credentials);
CookieStore cookieStore = new BasicCookieStore();
//SSL solution
CloseableHttpClient httpclient
= HttpClients.custom().setDefaultCookieStore(cookieStore)
.setDefaultCredentialsProvider(credsProvider).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);
//Массив headers (для тестов)
Header[] headers = response.getAllHeaders();
for (Header header : headers) {
System.out.println(header);
}
System.out.println();
Map<String, String> wwwAuth = Arrays
.stream(response.getHeaders("WWW-Authenticate")[0]
.getElements())
.collect(Collectors.toMap(HeaderElement::getName,
HeaderElement::getValue));
//Выведем наш массивчик чтобы лицезреть
for(Map.Entry<String, String> pair : wwwAuth.entrySet()){
System.out.println(pair.getKey() + " = " + pair.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();
}
}
}
When the program reaches this step:
Map<String, String> wwwAuth = Arrays
.stream(response.getHeaders("WWW-Authenticate")[0]
.getElements())
.collect(Collectors.toMap(HeaderElement::getName,
HeaderElement::getValue));
then "response: HTTP / 1.1 200 OK" and the program exits to exception

Using WinHttpClients from Apache Http Components

I have been able to successfully authentication to a service that requires ntlm authentication when using the WinHttpClients and a GET request. However when I try to do a POST I always get a 401 return code. Has anyone done this sucessfully before?
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.NTCredentials;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.WinHttpClients;
public class WindowsAuthPOst {
public static void main (String []args) throws Exception, IOException
{
org.apache.log4j.BasicConfigurator.configure();
CloseableHttpClient httpclient = WinHttpClients.createDefault();
HttpHost target = new HttpHost("SomeHost.domain", 443, "https");
HttpClientContext context = HttpClientContext.create();
HttpGet httpget = new HttpGet("/some/Service.svc");
CloseableHttpResponse response1 = httpclient.execute(target, httpget, context);
try {
HttpEntity entity1 = response1.getEntity();
} finally {
response1.close();
}
// Execute an expensive method next reusing the same context (and connection)
HttpPost httppost = new HttpPost("/some/Service.svc");
httppost.setHeader("SOAPAction", "Some Soap Action");
httppost.setEntity(new StringEntity("Soap Payload"));
CloseableHttpResponse response2 = httpclient.execute(target, httppost, context);
try {
HttpEntity entity2 = response2.getEntity();
} finally {
response2.close();
}
}
}
You can check if it is available with.
if (!WinHttpClients.isWinAuthAvailable()) {
System.out.println("Integrated Win auth is not supported!!!");
}
If not, it could be that you do not have jna.jar in your classpath. It depends on jna and will silently return false on the above if it not there, see source code.
Try with get (or options) before post. Some webservers requires that because of CORS.
https://stackoverflow.com/a/38410411/2376661

Twilio Rest Client and setting proxy

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

Apache HttpClient Digest Authentication Failed

I am tring to perform Digest Authentication using the HttpClient library, but I keep getting: HTTP/1.1 401 Unauthorized.
When I try the request from Firefox it works fine and I get a response correctly, so I know the server authentication is working fine.
Update: moved Working code to answer.
The following code worked for me
import java.util.Random;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthCache;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.auth.DigestScheme;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.impl.client.BasicAuthCache;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.util.EntityUtils;
/**
* A simple example that uses HttpClient to execute an HTTP request against a
* target site that requires user authentication.
*/
public class RestClient {
public static void main(String args[]) throws Exception {
HttpHost targetHost = new HttpHost("localhost", 8001, "http");
DefaultHttpClient httpclient = new DefaultHttpClient();
final String userName = "admin";
final String password = "password";
httpclient.getCredentialsProvider().setCredentials(
new AuthScope("localhost", 8001),
new UsernamePasswordCredentials(userName, password));
// Create AuthCache instance
AuthCache authCache = new BasicAuthCache();
// Generate DIGEST scheme object, initialize it and add it to the local
// auth cache
DigestScheme digestAuth = new DigestScheme();
// Suppose we already know the realm name
digestAuth.overrideParamter("realm", "some realm");
// Suppose we already know the expected nonce value
digestAuth.overrideParamter("nonce", "whatever");
authCache.put(targetHost, digestAuth);
// Add AuthCache to the execution context
BasicHttpContext localcontext = new BasicHttpContext();
localcontext.setAttribute(ClientContext.AUTH_CACHE, authCache);
HttpGet httpget = new HttpGet("http://localhost:8001/rest/test");
try {
HttpResponse response = httpclient.execute(targetHost, httpget, localcontext);
HttpEntity entity = response.getEntity();
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
if (entity != null) {
System.out.println("Response content length: " + entity.getContentLength());
}
EntityUtils.consume(entity);
} finally {
httpclient.getConnectionManager().shutdown();
}
}
}

Categories