package com.appdynamics.monitors.azure.request;
import com.appdynamics.monitors.azure.authenticator.BlobQueueSharedKeyAuth;
import com.appdynamics.monitors.azure.authenticator.TableSharedKeyAuth;
import com.appdynamics.monitors.azure.beans.ProxyDetails;
import com.google.common.base.Strings;
import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.Authenticator;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.PasswordAuthentication;
import java.net.ProtocolException;
import java.net.Proxy;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TimeZone;
public class AzureHttpsClient {
private static final Logger LOG = Logger.getLogger(AzureHttpsClient.class);
public static final String REQUEST_METHOD_GET = "GET";
public static final String X_MS_VERSION_HEADER = "x-ms-version";
public static final String CONTENT_TYPE_HEADER = "Content-Type";
public static final String ACCEPT_HEADER = "Accept";
public static final String CONTENT_TYPE_XML = "application/atom+xml";
public static final String ACCEPT_TYPE_XML = "application/atom+xml,application/xml";
public static final String X_MS_DATE_HEADER = "x-ms-date";
public static final String DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss z";
public static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat(DATE_FORMAT);
public static final String AUTHORIZATION_HEADER = "Authorization";
public static final String X_MS_VERSION = "2013-08-15";
private final ProxyDetails proxyDetails;
public AzureHttpsClient(ProxyDetails proxyDetails) {
this.proxyDetails = proxyDetails;
}
private KeyStore getKeyStore(String keyStoreName, String password) {
KeyStore ks = null;
FileInputStream fis = null;
try {
ks = KeyStore.getInstance("JKS");
char[] passwordArray = password.toCharArray();
fis = new java.io.FileInputStream(keyStoreName);
ks.load(fis, passwordArray);
fis.close();
} catch (CertificateException e) {
LOG.error(e.getMessage(), e);
throw new RuntimeException(e.getMessage(), e);
} catch (NoSuchAlgorithmException e) {
LOG.error(e.getMessage(), e);
throw new RuntimeException(e.getMessage(), e);
} catch (KeyStoreException e) {
LOG.error(e.getMessage(), e);
throw new RuntimeException(e.getMessage(), e);
} catch (FileNotFoundException e) {
LOG.error(e.getMessage(), e);
throw new RuntimeException(e.getMessage(), e);
} catch (IOException e) {
LOG.error(e.getMessage(), e);
throw new RuntimeException(e.getMessage(), e);
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
LOG.error(e.getMessage(), e);
}
}
}
return ks;
}
private SSLSocketFactory getSSLSocketFactory(String keyStoreName, String password) {
KeyStore ks = getKeyStore(keyStoreName, password);
KeyManagerFactory keyManagerFactory = null;
try {
keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
keyManagerFactory.init(ks, password.toCharArray());
SSLContext context = SSLContext.getInstance("TLS");
context.init(keyManagerFactory.getKeyManagers(), null, new SecureRandom());
return context.getSocketFactory();
} catch (NoSuchAlgorithmException e) {
LOG.error(e.getMessage(), e);
throw new RuntimeException(e.getMessage(), e);
} catch (KeyStoreException e) {
LOG.error(e.getMessage(), e);
throw new RuntimeException(e.getMessage(), e);
} catch (UnrecoverableKeyException e) {
LOG.error(e.getMessage(), e);
throw new RuntimeException(e.getMessage(), e);
} catch (KeyManagementException e) {
LOG.error(e.getMessage(), e);
throw new RuntimeException(e.getMessage(), e);
}
}
public Document processGetRequest(URL url, String restApiVersion, String keyStore, String keyStorePassword) {
SSLSocketFactory sslFactory = getSSLSocketFactory(keyStore, keyStorePassword);
HttpsURLConnection con = null;
try {
con = createConnection(url, proxyDetails);
} catch (IOException e) {
LOG.error(e.getMessage(), e);
throw new RuntimeException(e.getMessage(), e);
}
con.setSSLSocketFactory(sslFactory);
try {
con.setRequestMethod(REQUEST_METHOD_GET);
} catch (ProtocolException e) {
LOG.error(e.getMessage(), e);
throw new RuntimeException(e.getMessage(), e);
}
con.addRequestProperty(X_MS_VERSION_HEADER, restApiVersion);
InputStream responseStream = null;
try {
responseStream = (InputStream) con.getContent();
Document document = parseResponse(responseStream);
return document;
} catch (IOException e) {
LOG.error(e.getMessage(), e);
throw new RuntimeException(e.getMessage(), e);
} finally {
if (responseStream != null) {
try {
responseStream.close();
} catch (IOException e) {
LOG.error(e.getMessage(), e);
}
}
}
}
public URL buildRequestUrl(String urlString, String... subscriptionId) {
String subscriptionURL = String.format(urlString, subscriptionId);
URL url = null;
try {
url = new URL(subscriptionURL);
} catch (MalformedURLException e) {
LOG.error(e.getMessage(), e);
throw new RuntimeException(e.getMessage(), e);
}
return url;
}
private Document parseResponse(InputStream responseStream) {
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = null;
try {
documentBuilder = builderFactory.newDocumentBuilder();
} catch (ParserConfigurationException e) {
LOG.error(e.getMessage(), e);
throw new RuntimeException(e.getMessage(), e);
}
Document document = null;
try {
document = documentBuilder.parse(responseStream);
} catch (SAXException e) {
LOG.error(e.getMessage(), e);
throw new RuntimeException(e.getMessage(), e);
} catch (IOException e) {
LOG.error(e.getMessage(), e);
throw new RuntimeException(e.getMessage(), e);
}
document.getDocumentElement().normalize();
return document;
}
public Document createHttpConnectionWithHeadersForTable(String uri, String accountName, String accountKey) {
try {
URL myURL = new URL(uri);
HttpsURLConnection con = createConnection(myURL, proxyDetails);
setDefaultHeaders(con);
String utcDate = getUTCDate();
con.setRequestProperty(X_MS_DATE_HEADER, utcDate);
TableSharedKeyAuth tableSharedKeyAuth = new TableSharedKeyAuth(accountName, accountKey);
String sign = tableSharedKeyAuth.sign(REQUEST_METHOD_GET, "", CONTENT_TYPE_XML, utcDate, myURL);
con.setRequestProperty(AUTHORIZATION_HEADER, sign);
InputStream responseStream = (InputStream) con.getContent();
try {
Document document = parseResponse(responseStream);
return document;
} finally {
responseStream.close();
}
} catch (IOException e) {
LOG.error(e.getMessage(), e);
throw new RuntimeException(e.getMessage(), e);
}
}
public Document processRequestWithHeadersForBlobQueue(String uri, String accountName, String accountKey) {
try {
URL myURL = new URL(uri);
HttpsURLConnection con = createConnection(myURL, proxyDetails);
setDefaultHeaders(con);
String utcDate = getUTCDate();
con.setRequestProperty(X_MS_DATE_HEADER, utcDate);
BlobQueueSharedKeyAuth blobQueueSharedKeyAuth = new BlobQueueSharedKeyAuth(accountName, accountKey);
Map<String, String> headers = new LinkedHashMap<String, String>();
headers.put(X_MS_DATE_HEADER, utcDate);
headers.put(X_MS_VERSION_HEADER, X_MS_VERSION);
String sign = blobQueueSharedKeyAuth.sign(REQUEST_METHOD_GET, headers, myURL);
con.setRequestProperty(AUTHORIZATION_HEADER, sign);
InputStream responseStream = (InputStream) con.getContent();
try {
Document document = parseResponse(responseStream);
return document;
} finally {
responseStream.close();
}
} catch (IOException e) {
LOG.error(e.getMessage(), e);
throw new RuntimeException(e.getMessage(), e);
}
}
private HttpsURLConnection createConnection(URL url, final ProxyDetails proxyDetails) throws IOException {
HttpsURLConnection con = null;
if (proxyDetails != null && !Strings.isNullOrEmpty(proxyDetails.getProxyHost())) {
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyDetails.getProxyHost(), proxyDetails.getProxyPort()));
con = (HttpsURLConnection) url.openConnection(proxy);
if (!Strings.isNullOrEmpty(proxyDetails.getProxyUsername()) && !Strings.isNullOrEmpty(proxyDetails.getProxyPassword())) {
Authenticator authenticator = new Authenticator() {
public PasswordAuthentication getPasswordAuthentication() {
return (new PasswordAuthentication(proxyDetails.getProxyUsername(),
proxyDetails.getProxyPassword().toCharArray()));
}
};
Authenticator.setDefault(authenticator);
}
} else {
con = (HttpsURLConnection) url.openConnection();
}
return con;
}
private void setDefaultHeaders(HttpURLConnection con) throws ProtocolException {
con.setRequestMethod(REQUEST_METHOD_GET);
con.setRequestProperty(X_MS_VERSION_HEADER, X_MS_VERSION);
con.setRequestProperty(CONTENT_TYPE_HEADER, CONTENT_TYPE_XML);
con.setRequestProperty(ACCEPT_HEADER, ACCEPT_TYPE_XML);
}
private static String getUTCDate() {
SIMPLE_DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT"));
return SIMPLE_DATE_FORMAT.format(new Date());
}
}