package com.redhat.qe.tools;
import java.net.URI;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.logging.Logger;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLException;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.annotation.NotThreadSafe;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import oauth.signpost.OAuth;
import oauth.signpost.OAuthConsumer;
import oauth.signpost.commonshttp.CommonsHttpOAuthConsumer;
import java.io.IOException;
public class HttpClient {
private static DefaultHttpClient httpclient = new DefaultHttpClient();
private static Logger log = Logger.getLogger(HttpClient.class.getName());
private static OAuthConsumer consumer = null;
public static void setOAuthCredentials(String key, String secret) {
log.info("Setting client oath key to " + key);
log.info("Setting client oath secret to " + secret);
consumer = new CommonsHttpOAuthConsumer(key, secret);
}
public static String[] getRequest(String protocol, String server, String port, String path, String username, String password, String sContentType, String sAcceptHeader, NameValuePair[] nvpList) throws Exception {
HttpGet get = new HttpGet( buildUrl(protocol,server,port,path) );
return finishRequest(get, username, password, null, sContentType, sAcceptHeader, nvpList);
}
public static String[] postRequest(String protocol, String server, String port, String path, String username, String password, String requestBody, String sContentType, String sAcceptHeader, NameValuePair[] nvpList) throws Exception {
HttpPost post = new HttpPost( buildUrl(protocol,server,port,path) );
return finishRequest(post, username, password, requestBody, sContentType, sAcceptHeader, nvpList);
}
public static String[] putRequest(String protocol, String server, String port, String path, String username, String password, String requestBody, String sContentType, String sAcceptHeader, NameValuePair[] nvpList) throws Exception {
HttpPut put = new HttpPut( buildUrl(protocol,server,port,path) );
return finishRequest(put, username, password, requestBody, sContentType, sAcceptHeader, nvpList);
}
public static String[] deleteRequest(String protocol, String server, String port, String path, String username, String password, String requestBody, String sContentType, String sAcceptHeader) throws Exception {
HttpDeleteWithBody delete = new HttpDeleteWithBody( buildUrl(protocol,server,port,path) );
return finishRequest(delete, username, password, requestBody, sContentType, sAcceptHeader, null);
}
private static String[] finishRequest(HttpUriRequest method, String username, String password, String requestBody, String sContentType, String sAcceptHeader, NameValuePair[] nvpList) throws Exception {
String sArgs = "";
if (requestBody != null) {
if ( requestBody.contains("&") && !requestBody.contains("&&") ) {
String[] items = requestBody.split("&");
for (String i: items)
sArgs += " -d " + i;
} else
sArgs += " -d '" + requestBody + "'";
}
if (nvpList != null) {
for (NameValuePair key: nvpList) {
key.getName();
key.getValue();
sArgs += " -d " + key.getName() + "='" + key.getValue() + "'";
if (requestBody == null)
requestBody = key.getName() + "=" + key.getValue() + "";
else
requestBody += "&" + key.getName() + "=" + key.getValue() + "";
}
}
if (sContentType != null)
sArgs += " -H \"Content-Type: " + sContentType + "\"";
method.addHeader("Content-Type", sContentType);
if (sAcceptHeader != null) {
sArgs += " -H \"Accept: " + sAcceptHeader + "\"";
method.addHeader("Accept", sAcceptHeader);
}
if (requestBody != null) {
StringEntity entity = new StringEntity(requestBody, HTTP.UTF_8);
BasicHeader basicHeader = new BasicHeader(HTTP.CONTENT_TYPE,sContentType);
entity.setContentType(basicHeader);
if (method instanceof HttpPut)
((HttpPut)method).setEntity(entity);
else if (method instanceof HttpPost)
((HttpPost)method).setEntity(entity);
else if (method instanceof HttpDeleteWithBody)
((HttpDeleteWithBody)method).setEntity(entity);
}
if (method.getURI().getScheme().equalsIgnoreCase("https")) {
sArgs += " --insecure";
setupHTTPS(method);
}
if (consumer != null) {
consumer.sign(method);
} else if ((username != null) && (password != null)) {
sArgs += " -u " + username + ":" + password;
// http://stackoverflow.com/questions/2014700/preemptive-basic-authentication-with-apache-httpclient-4
// forcing authentication (needed for conductor api)
UsernamePasswordCredentials creds = new UsernamePasswordCredentials(username, password);
method.addHeader(new BasicScheme().authenticate(creds, method));
setCredentials(method.getURI().getHost(), method.getURI().getPort(), username, password);
}
log.info("cmdline curl equivalent: curl -X " +method.getMethod().toString() + sArgs +" "+ method.getURI() );
return processRequest(method, username, password);
}
private static void setCredentials(String fqdn, int port, String username, String password) {
if (!username.equals(""))
httpclient.getCredentialsProvider().setCredentials(
new AuthScope(fqdn, port),
new UsernamePasswordCredentials(username, password));
}
private static void setupHTTPS(HttpUriRequest method) throws NoSuchAlgorithmException, KeyManagementException {
// Override check cert validity to avoid SSL handshake exception
// http://stackoverflow.com/questions/1828775/httpclient-and-ssl
TrustManager easyTrustManager = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
// do nothing
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
// do nothing
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
X509HostnameVerifier verifier = new X509HostnameVerifier() {
@Override
public void verify(String string, SSLSocket ssls) throws IOException {
}
@Override
public void verify(String string, X509Certificate xc) throws SSLException {
}
@Override
public void verify(String string, String[] strings, String[] strings1) throws SSLException {
}
@Override
public boolean verify(String string, SSLSession ssls) {
return true;
}
};
SSLContext sslcontext = SSLContext.getInstance("SSL");
sslcontext.init(null, new TrustManager[] { easyTrustManager }, null);
SSLSocketFactory socketFactory = new SSLSocketFactory(sslcontext);
socketFactory.setHostnameVerifier(verifier);
Scheme sch = new Scheme("https", method.getURI().getPort()==-1?443:method.getURI().getPort(), socketFactory);
httpclient.getConnectionManager().getSchemeRegistry().register(sch);
}
private static String[] processRequest(HttpUriRequest method, String username, String password) throws Exception {
String[] response = new String[2];
String server = method.getURI().getHost();
HttpResponse httpResponse = httpclient.execute(method);
response[0] = Integer.toString(httpResponse.getStatusLine().getStatusCode());
HttpEntity entity = httpResponse.getEntity();
if (entity != null) {
//long len = entity.getContentLength();
response[1] = EntityUtils.toString(entity);
}
return response;
}
// We override HttpEntityEnclosingRequestBase in order to allow a body to be passed in a delete request
// Needed for RhevmApiClient class
// http://stackoverflow.com/questions/3773338/httpdelete-with-body
@NotThreadSafe
private static class HttpDeleteWithBody extends HttpEntityEnclosingRequestBase {
public static final String METHOD_NAME = "DELETE";
public String getMethod() { return METHOD_NAME; }
public HttpDeleteWithBody(final String uri) {
super();
setURI(URI.create(uri));
}
public HttpDeleteWithBody(final URI uri) {
super();
setURI(uri);
}
public HttpDeleteWithBody() { super(); }
}
private static String buildUrl(String protocol, String server, String port, String path) {
return (port == null) ? protocol + "://"+server+path : protocol + "://"+server+":"+port+path;
}
}