/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.threatconnect.sdk.conn;
import com.threatconnect.app.apps.AppConfig;
import com.threatconnect.sdk.config.Configuration;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.AbstractHttpMessage;
import org.apache.http.ssl.SSLContextBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.Properties;
/**
* @author dtineo
*/
public class ConnectionUtil
{
private static final Logger logger = LoggerFactory.getLogger(ConnectionUtil.class.getSimpleName());
public static Properties loadProperties(String fileName) throws IOException
{
Properties props = new Properties();
try
{
// check classloader, if running in container, this will fail on NPE
InputStream in = ConnectionUtil.class.getResourceAsStream(fileName);
props.load(in);
}
catch (NullPointerException npe)
{
props = new Properties();
InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);
props.load(in);
}
return props;
}
public static String getHmacSha256Signature(String signature, String apiSecretKey)
{
try
{
String calculatedSignature;
SecretKeySpec spec = new SecretKeySpec(apiSecretKey.getBytes(), "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(spec);
byte[] rawSignature = mac.doFinal(signature.getBytes());
calculatedSignature = Base64.encodeBase64String(rawSignature);
return calculatedSignature;
}
catch (NoSuchAlgorithmException | InvalidKeyException | IllegalStateException ex)
{
logger.error("Error creating HMAC SHA256 signature", ex);
return null;
}
}
private static String getSignature(Long headerTimestamp, String httpMethod, String urlPath, String urlQuery)
{
String query = (urlQuery == null ? "" : "?" + urlQuery);
return String.format("%s%s:%s:%d", urlPath, query, httpMethod, headerTimestamp);
}
static void applyHeaders(Configuration config, AbstractHttpMessage message, String httpMethod, String urlPath)
{
applyHeaders(config, message, httpMethod, urlPath, null);
}
static void applyHeaders(Configuration config, AbstractHttpMessage message, String httpMethod, String urlPath,
String contentType)
{
applyHeaders(config, message, httpMethod, urlPath, contentType, config.getContentType());
}
static void applyHeaders(Configuration config, AbstractHttpMessage message, String httpMethod, String urlPath,
String contentType, String acceptType)
{
if (config.getTcToken() != null)
{
message.addHeader("authorization", "TC-Token " + config.getTcToken());
}
else
{
Long ts = System.currentTimeMillis() / 1000L;
String sig = getSignature(ts, httpMethod, urlPath, null);
String hmacSig = getHmacSha256Signature(sig, config.getTcApiUserSecretKey());
String auth = getAuthorizationText(config, hmacSig);
message.addHeader("timestamp", "" + ts);
message.addHeader("authorization", auth);
}
message.addHeader("Accept", acceptType);
if (contentType != null)
{
message.addHeader("Content-Type", contentType);
}
}
private static String getAuthorizationText(Configuration config, String hmacSig)
{
return String.format("TC %s:%s", config.getTcApiAccessID(), hmacSig);
}
/**
* Adds proxy information to an http client builder
*
* @param builder
* the HttpClientBuilder builder to add the proxy information to
* @param proxyHost
* the host of the proxy server
* @param proxyPort
* the port of the proxy server
* @param proxyUserName
* the username to authenticate with the proxy server (optional)
* @param proxyPassword
* the password to authenticate with the proxy server (optional)
*/
public static void addProxy(final HttpClientBuilder builder, final String proxyHost,
final Integer proxyPort, final String proxyUserName, final String proxyPassword)
{
// check to see if the the host or port are null
if (proxyHost == null || proxyPort == null)
{
logger.warn("proxyHost and proxyPort are required to connect to a proxy");
}
else
{
// add the proxy information to the builder
builder.setProxy(new HttpHost(proxyHost, proxyPort));
// authentication required
if (proxyUserName != null && proxyPassword != null)
{
// add the credentials to the proxy information
Credentials credentials = new UsernamePasswordCredentials(proxyUserName, proxyPassword);
AuthScope authScope = new AuthScope(proxyHost, proxyPort);
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(authScope, credentials);
builder.setDefaultCredentialsProvider(credsProvider);
}
}
}
/**
* Adds the ability to trust self signed certificates for this HttpClientBuilder
*
* @param httpClientBuilder
* the HttpClientBuilder to apply these settings to
*/
public static void trustSelfSignedCerts(final HttpClientBuilder httpClientBuilder)
{
logger.debug("Trusting self-signed certs.");
try
{
SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
builder.build(), new HostnameVerifier()
{
@Override
public boolean verify(String hostname, SSLSession session)
{
// allow all
return true;
}
});
httpClientBuilder.setSSLSocketFactory(sslsf);
}
catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException ex)
{
logger.error("Error adding SSLSocketFactory to HttpClientBuilder", ex);
}
}
/**
* Creates a new CloseableHttpClient
*
* @return the new http client
*/
public static CloseableHttpClient createClient()
{
return createClient(null, null);
}
/**
* Creates a new CloseableHttpClient
*
* @param trustSelfSignedCertificates
* whether or not self signed certificates should be trusted
* @return the new http client
*/
public static CloseableHttpClient createClient(boolean trustSelfSignedCertificates)
{
return createClient(null, null, null, null, trustSelfSignedCertificates);
}
/**
* Creates a new CloseableHttpClient
*
* @param proxyHost
* the host of the proxy server (optional)
* @param proxyPort
* the port of the proxy server (optional)
* @return the new http client
*/
public static CloseableHttpClient createClient(final String proxyHost, Integer proxyPort)
{
return createClient(proxyHost, proxyPort, null, null);
}
/**
* Creates a new CloseableHttpClient
*
* @param proxyHost
* the host of the proxy server (optional)
* @param proxyPort
* the port of the proxy server (optional)
* @param proxyUserName
* the username to authenticate with the proxy server (optional)
* @param proxyPassword
* the password to authenticate with the proxy server (optional)
* @return the new http client
*/
public static CloseableHttpClient createClient(final String proxyHost, Integer proxyPort, String proxyUserName,
String proxyPassword)
{
return createClient(proxyHost, proxyPort, proxyUserName, proxyPassword, false);
}
/**
* Creates a builder for an HttpClient
*
* @param proxyHost
* the host of the proxy server (optional)
* @param proxyPort
* the port of the proxy server (optional)
* @param proxyUserName
* the username to authenticate with the proxy server (optional)
* @param proxyPassword
* the password to authenticate with the proxy server (optional)
* @param trustSelfSignedCertificates
* whether or not self signed certificates should be trusted
* @return the new http client
*/
public static HttpClientBuilder createClientBuilder(final String proxyHost, Integer proxyPort, String proxyUserName,
String proxyPassword, boolean trustSelfSignedCertificates)
{
// create a new http client builder
HttpClientBuilder builder = HttpClients.custom();
// allow self signed certificates
if (trustSelfSignedCertificates)
{
trustSelfSignedCerts(builder);
}
// check to see if there are proxy settings
if (null != proxyHost && null != proxyPort)
{
// apply the proxy settings
addProxy(builder, proxyHost, proxyPort, proxyUserName, proxyPassword);
}
return builder;
}
/**
* Creates a new CloseableHttpClient
*
* @param proxyHost
* the host of the proxy server (optional)
* @param proxyPort
* the port of the proxy server (optional)
* @param proxyUserName
* the username to authenticate with the proxy server (optional)
* @param proxyPassword
* the password to authenticate with the proxy server (optional)
* @param trustSelfSignedCertificates
* whether or not self signed certificates should be trusted
* @return the new http client
*/
public static CloseableHttpClient createClient(final String proxyHost, Integer proxyPort, String proxyUserName,
String proxyPassword, boolean trustSelfSignedCertificates)
{
return createClientBuilder(proxyHost, proxyPort, proxyUserName, proxyPassword, trustSelfSignedCertificates)
.build();
}
/**
* Creates the configuration object from an AppConfig
*
* @param appConfig
* @return
*/
public static Configuration createConfiguration(final AppConfig appConfig)
{
// create the configuration for the threatconnect server
Configuration configuration = new Configuration(appConfig.getTcApiPath(), appConfig.getTcApiAccessID(),
appConfig.getTcApiUserSecretKey(), appConfig.getApiDefaultOrg(), appConfig.getTcToken(), appConfig.getTcTokenExpires());
return configuration;
}
}