datahub/datahub-frontend/app/react/analytics/AnalyticsServiceModule.java
John Joyce 29832e5385
feat(Product Analytics): Introducing In-App Analytics Beta (#2499)
Co-authored-by: Harshal Sheth <harshal@acryl.io>
Co-authored-by: Dexter Lee <dexter@acryl.io>
Co-authored-by: Gabe Lyons <itsgabelyons@gmail.com>
2021-05-11 15:41:42 -07:00

129 lines
6.7 KiB
Java

package react.analytics;
import com.google.inject.AbstractModule;
import org.apache.http.ssl.SSLContextBuilder;
import play.Environment;
import javax.annotation.Nonnull;
import javax.net.ssl.SSLContext;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
/**
* Guice module responsible for configuring & creating an instance of {@link AnalyticsService}.
*/
public class AnalyticsServiceModule extends AbstractModule {
/*
Required Config Paths
*/
private static final String ELASTIC_CLIENT_HOST_PATH = "analytics.elastic.host";
private static final String ELASTIC_CLIENT_PORT_PATH = "analytics.elastic.port";
/*
Optional Config Paths
*/
private static final String ELASTIC_CLIENT_USE_SSL_PATH = "analytics.elastic.useSSL";
private static final String ELASTIC_CLIENT_THREAD_COUNT_PATH = "analytics.elastic.threadCount";
private static final String ELASTIC_CLIENT_CONNECTION_REQUEST_TIMEOUT_PATH = "analytics.elastic.connectionRequestTimeout";
private static final String ELASTIC_CLIENT_USERNAME_PATH = "analytics.elastic.username";
private static final String ELASTIC_CLIENT_PASSWORD_PATH = "analytics.elastic.password";
/*
Required SSL Config Paths
*/
private static final String ELASTIC_CLIENT_SSL_PROTOCOL_PATH = "analytics.elastic.sslContext.sslProtocol";
private static final String ELASTIC_CLIENT_SSL_SECURE_RANDOM_IMPL_PATH = "analytics.elastic.sslContext.sslSecureRandomImplementation";
private static final String ELASTIC_CLIENT_SSL_TRUST_STORE_FILE_PATH = "analytics.elastic.sslContext.sslTrustStoreFile";
private static final String ELASTIC_CLIENT_SSL_TRUST_STORE_TYPE_PATH = "analytics.elastic.sslContext.sslTrustStoreType";
private static final String ELASTIC_CLIENT_SSL_TRUST_STORE_PASSWORD_PATH = "analytics.elastic.sslContext.sslTrustStorePassword";
private static final String ELASTIC_CLIENT_SSL_KEY_STORE_FILE_PATH = "analytics.elastic.sslContext.sslKeyStoreFile";
private static final String ELASTIC_CLIENT_SSL_KEY_STORE_TYPE_PATH = "analytics.elastic.sslContext.sslKeyStoreType";
private static final String ELASTIC_CLIENT_SSL_KEY_STORE_PASSWORD_PATH = "analytics.elastic.sslContext.sslKeyStorePassword";
/*
Default values
*/
private static final Integer DEFAULT_THREAD_COUNT = 1;
private static final Integer DEFAULT_CONNECTION_TIMEOUT = 50;
private final com.typesafe.config.Config _configs;
public AnalyticsServiceModule(final Environment environment, final com.typesafe.config.Config configs) {
_configs = configs;
}
@Override
protected void configure() {
final SSLContext context = createSSLContext();
final AnalyticsService backend = new AnalyticsService(ElasticClientFactory.createElasticClient(
_configs.hasPath(ELASTIC_CLIENT_USE_SSL_PATH) && _configs.getBoolean(ELASTIC_CLIENT_USE_SSL_PATH),
_configs.getString(ELASTIC_CLIENT_HOST_PATH),
_configs.getInt(ELASTIC_CLIENT_PORT_PATH),
_configs.hasPath(ELASTIC_CLIENT_THREAD_COUNT_PATH) ? _configs.getInt(ELASTIC_CLIENT_THREAD_COUNT_PATH) : DEFAULT_THREAD_COUNT,
_configs.hasPath(ELASTIC_CLIENT_CONNECTION_REQUEST_TIMEOUT_PATH) ? _configs.getInt(ELASTIC_CLIENT_CONNECTION_REQUEST_TIMEOUT_PATH) : DEFAULT_CONNECTION_TIMEOUT,
_configs.hasPath(ELASTIC_CLIENT_USERNAME_PATH) ? _configs.getString(ELASTIC_CLIENT_USERNAME_PATH) : null,
_configs.hasPath(ELASTIC_CLIENT_PASSWORD_PATH) ? _configs.getString(ELASTIC_CLIENT_PASSWORD_PATH) : null,
context
));
bind(AnalyticsService.class).toInstance(backend);
}
private SSLContext createSSLContext() {
if (!_configs.hasPath(ELASTIC_CLIENT_USE_SSL_PATH) || !_configs.getBoolean(ELASTIC_CLIENT_USE_SSL_PATH)) {
// SSL Disabled
return null;
}
final String sslProtocol = _configs.getString(ELASTIC_CLIENT_SSL_PROTOCOL_PATH);
final String sslSecureRandomImplementation = _configs.getString(ELASTIC_CLIENT_SSL_SECURE_RANDOM_IMPL_PATH);
final String sslTrustStoreFile = _configs.getString(ELASTIC_CLIENT_SSL_TRUST_STORE_FILE_PATH);
final String sslTrustStoreType = _configs.getString(ELASTIC_CLIENT_SSL_TRUST_STORE_TYPE_PATH);
final String sslTrustStorePassword = _configs.getString(ELASTIC_CLIENT_SSL_TRUST_STORE_PASSWORD_PATH);
final String sslKeyStoreFile = _configs.getString(ELASTIC_CLIENT_SSL_KEY_STORE_FILE_PATH);
final String sslKeyStoreType = _configs.getString(ELASTIC_CLIENT_SSL_KEY_STORE_TYPE_PATH);
final String sslKeyStorePassword = _configs.getString(ELASTIC_CLIENT_SSL_KEY_STORE_PASSWORD_PATH);
final SSLContextBuilder sslContextBuilder = new SSLContextBuilder();
if (sslProtocol != null) {
sslContextBuilder.useProtocol(sslProtocol);
}
if (sslTrustStoreFile != null && sslTrustStoreType != null && sslTrustStorePassword != null) {
loadKeyStore(sslContextBuilder, sslTrustStoreFile, sslTrustStoreType, sslTrustStorePassword);
}
if (sslKeyStoreFile != null && sslKeyStoreType != null && sslKeyStorePassword != null) {
loadKeyStore(sslContextBuilder, sslKeyStoreFile, sslKeyStoreType, sslKeyStorePassword);
}
final SSLContext sslContext;
try {
if (sslSecureRandomImplementation != null) {
sslContextBuilder.setSecureRandom(SecureRandom.getInstance(sslSecureRandomImplementation));
}
sslContext = sslContextBuilder.build();
} catch (NoSuchAlgorithmException | KeyManagementException e) {
throw new RuntimeException("Failed to build SSL Context", e);
}
return sslContext;
}
private void loadKeyStore(@Nonnull SSLContextBuilder sslContextBuilder,
@Nonnull String path,
@Nonnull String type,
@Nonnull String password) {
try (InputStream identityFile = new FileInputStream(path)) {
final KeyStore keystore = KeyStore.getInstance(type);
keystore.load(identityFile, password.toCharArray());
sslContextBuilder.loadTrustMaterial(keystore, null);
} catch (IOException | CertificateException | NoSuchAlgorithmException | KeyStoreException e) {
throw new RuntimeException("Failed to load key store: " + path, e);
}
}
}