diff --git a/contrib/storage-splunk/README.md b/contrib/storage-splunk/README.md index 29e1b426737..08e3d65de80 100644 --- a/contrib/storage-splunk/README.md +++ b/contrib/storage-splunk/README.md @@ -3,21 +3,22 @@ This plugin enables Drill to query Splunk. ## Configuration -| Option | Default | Description | Since | -| -------------------- | --------- | --------------------------------------------------------------- | ----- | -| type | (none) | Set to "splunk" to use this plugin | 1.19 | -| username | null | Splunk username to be used by Drill | 1.19 | -| password | null | Splunk password to be used by Drill | 1.19 | -| scheme | https | The scheme with which to access the Splunk host | 2.0 | -| hostname | localhost | Splunk host to be queried by Drill | 1.19 | -| port | 8089 | TCP port over which Drill will connect to Splunk | 1.19 | -| earliestTime | null | Global earliest record timestamp default | 1.19 | -| latestTime | null | Global latest record timestamp default | 1.19 | -| app | null | The application context of the service[^1] | 2.0 | -| owner | null | The owner context of the service[^1] | 2.0 | -| token | null | A Splunk authentication token to use for the session[^2] | 2.0 | -| cookie | null | A valid login cookie | 2.0 | -| validateCertificates | true | Whether the Splunk client will validates the server's SSL cert | 2.0 | +| Option | Default | Description | Since | +|-----------------------| --------- | --------------------------------------------------------------- | ----- | +| type | (none) | Set to "splunk" to use this plugin | 1.19 | +| username | null | Splunk username to be used by Drill | 1.19 | +| password | null | Splunk password to be used by Drill | 1.19 | +| scheme | https | The scheme with which to access the Splunk host | 2.0 | +| hostname | localhost | Splunk host to be queried by Drill | 1.19 | +| port | 8089 | TCP port over which Drill will connect to Splunk | 1.19 | +| earliestTime | null | Global earliest record timestamp default | 1.19 | +| latestTime | null | Global latest record timestamp default | 1.19 | +| app | null | The application context of the service[^1] | 2.0 | +| owner | null | The owner context of the service[^1] | 2.0 | +| token | null | A Splunk authentication token to use for the session[^2] | 2.0 | +| cookie | null | A valid login cookie | 2.0 | +| validateCertificates | true | Whether the Splunk client will validates the server's SSL cert | 2.0 | +| validateHostname | true | Whether the Splunk client will validate the server's host name | 1.22 | [^1]: See [this Splunk documentation](https://docs.splunk.com/Documentation/Splunk/latest/Admin/Apparchitectureandobjectownership) for more information. [^2]: See [this Splunk documentation](https://docs.splunk.com/Documentation/Splunk/latest/Security/CreateAuthTokens) for more information. diff --git a/contrib/storage-splunk/pom.xml b/contrib/storage-splunk/pom.xml index 1286c97b129..9a68a6ffa0f 100644 --- a/contrib/storage-splunk/pom.xml +++ b/contrib/storage-splunk/pom.xml @@ -50,7 +50,7 @@ com.splunk splunk - 1.9.3 + 1.9.5 org.apache.maven.plugins diff --git a/contrib/storage-splunk/src/main/java/org/apache/drill/exec/store/splunk/SplunkConnection.java b/contrib/storage-splunk/src/main/java/org/apache/drill/exec/store/splunk/SplunkConnection.java index 02cb431e81a..ec26f62c827 100644 --- a/contrib/storage-splunk/src/main/java/org/apache/drill/exec/store/splunk/SplunkConnection.java +++ b/contrib/storage-splunk/src/main/java/org/apache/drill/exec/store/splunk/SplunkConnection.java @@ -30,6 +30,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; @@ -37,9 +39,8 @@ import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.cert.X509Certificate; -import java.util.concurrent.TimeUnit; - import java.util.Optional; +import java.util.concurrent.TimeUnit; /** * This class wraps the functionality of the Splunk connection for Drill. @@ -54,6 +55,10 @@ public class SplunkConnection { private final Integer port; // Whether the Splunk client will validate the server's SSL cert. private final boolean validateCertificates; + + // Whether or not to validate the server's hostname. + private final boolean validateHostnames; + // The application context of the service. private final String app; // The owner context of the service. @@ -80,6 +85,7 @@ public SplunkConnection(SplunkPluginConfig config, String queryUserName) { this.token = config.getToken(); this.cookie = config.getCookie(); this.validateCertificates = config.getValidateCertificates(); + this.validateHostnames = config.getValidateHostname(); this.connectionAttempts = config.getReconnectRetries(); service = connect(); } @@ -101,6 +107,7 @@ public SplunkConnection(SplunkPluginConfig config, Service service, String query this.token = config.getToken(); this.cookie = config.getCookie(); this.validateCertificates = config.getValidateCertificates(); + this.validateHostnames = config.getValidateHostname(); this.service = service; } @@ -109,8 +116,9 @@ public SplunkConnection(SplunkPluginConfig config, Service service, String query * @return an active Splunk {@link Service} connection. */ public Service connect() { - HttpService.setSslSecurityProtocol(SSLSecurityProtocol.TLSv1_2); HttpService.setValidateCertificates(validateCertificates); + HttpService.setSslSecurityProtocol(SSLSecurityProtocol.TLSv1_2); + if (! validateCertificates) { try { HttpService.setSSLSocketFactory(createAllTrustingSSLFactory()); @@ -121,6 +129,16 @@ public Service connect() { } } + if (! this.validateHostnames) { + // Disable hostname verification + // This verification does not work with Splunk self-signed certificates + HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { + public boolean verify(String hostname, javax.net.ssl.SSLSession sslSession) { + return true; + } + }); + } + ServiceArgs loginArgs = new ServiceArgs(); if (scheme != null) { // Fall back to the Splunk SDK default if our value is null by not setting diff --git a/contrib/storage-splunk/src/main/java/org/apache/drill/exec/store/splunk/SplunkPluginConfig.java b/contrib/storage-splunk/src/main/java/org/apache/drill/exec/store/splunk/SplunkPluginConfig.java index 759c2a8d46e..7845abeac5e 100644 --- a/contrib/storage-splunk/src/main/java/org/apache/drill/exec/store/splunk/SplunkPluginConfig.java +++ b/contrib/storage-splunk/src/main/java/org/apache/drill/exec/store/splunk/SplunkPluginConfig.java @@ -20,6 +20,8 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonTypeName; import org.apache.drill.common.PlanStringBuilder; @@ -49,6 +51,7 @@ public class SplunkPluginConfig extends StoragePluginConfig { private final String token; private final String cookie; private final boolean validateCertificates; + private final boolean validateHostname; private final Integer reconnectRetries; private final boolean writable; private final Integer writerBatchSize; @@ -64,6 +67,7 @@ public SplunkPluginConfig(@JsonProperty("username") String username, @JsonProperty("token") String token, @JsonProperty("cookie") String cookie, @JsonProperty("validateCertificates") boolean validateCertificates, + @JsonProperty("validateHostname") boolean validateHostname, @JsonProperty("earliestTime") String earliestTime, @JsonProperty("latestTime") String latestTime, @JsonProperty("credentialsProvider") CredentialsProvider credentialsProvider, @@ -82,6 +86,7 @@ public SplunkPluginConfig(@JsonProperty("username") String username, this.cookie = cookie; this.writable = writable; this.validateCertificates = validateCertificates; + this.validateHostname = validateHostname; this.earliestTime = earliestTime; this.latestTime = latestTime == null ? "now" : latestTime; this.reconnectRetries = reconnectRetries; @@ -99,6 +104,7 @@ private SplunkPluginConfig(SplunkPluginConfig that, CredentialsProvider credenti this.writable = that.writable; this.cookie = that.cookie; this.validateCertificates = that.validateCertificates; + this.validateHostname = that.validateHostname; this.earliestTime = that.earliestTime; this.latestTime = that.latestTime; this.reconnectRetries = that.reconnectRetries; @@ -188,10 +194,17 @@ public String getCookie() { } @JsonProperty("validateCertificates") + @JsonInclude(Include.NON_DEFAULT) public boolean getValidateCertificates() { return validateCertificates; } + @JsonProperty("validateHostname") + @JsonInclude(Include.NON_DEFAULT) + public boolean getValidateHostname() { + return validateHostname; + } + @JsonProperty("earliestTime") public String getEarliestTime() { return earliestTime; @@ -234,6 +247,7 @@ public boolean equals(Object that) { Objects.equals(token, thatConfig.token) && Objects.equals(cookie, thatConfig.cookie) && Objects.equals(validateCertificates, thatConfig.validateCertificates) && + Objects.equals(validateHostname, thatConfig.validateHostname) && Objects.equals(earliestTime, thatConfig.earliestTime) && Objects.equals(latestTime, thatConfig.latestTime) && Objects.equals(authMode, thatConfig.authMode); @@ -252,6 +266,7 @@ public int hashCode() { cookie, writable, validateCertificates, + validateHostname, earliestTime, latestTime, authMode @@ -271,6 +286,7 @@ public String toString() { .field("token", token) .field("cookie", cookie) .field("validateCertificates", validateCertificates) + .field("validateHostname", validateHostname) .field("earliestTime", earliestTime) .field("latestTime", latestTime) .field("Authentication Mode", authMode) diff --git a/contrib/storage-splunk/src/main/java/org/apache/drill/exec/store/splunk/SplunkUtils.java b/contrib/storage-splunk/src/main/java/org/apache/drill/exec/store/splunk/SplunkUtils.java index a859f2cf5ab..4b856182f5d 100644 --- a/contrib/storage-splunk/src/main/java/org/apache/drill/exec/store/splunk/SplunkUtils.java +++ b/contrib/storage-splunk/src/main/java/org/apache/drill/exec/store/splunk/SplunkUtils.java @@ -18,8 +18,6 @@ package org.apache.drill.exec.store.splunk; -import java.util.Arrays; - public class SplunkUtils { /** * These are special fields that alter the queries sent to Splunk. @@ -54,9 +52,13 @@ public enum SPECIAL_FIELDS { * @param unknownField The field to be pushed down * @return true if the field is a special field, false if not. */ - public static boolean includes(String field) { - return Arrays.stream(SplunkUtils.SPECIAL_FIELDS.values()) - .anyMatch(special -> field.equals(special.name())); + public static boolean includes(String unknownField) { + for (SPECIAL_FIELDS field : SPECIAL_FIELDS.values()) { + if (field.field.equals(unknownField)) { + return true; + } + } + return false; } } } diff --git a/contrib/storage-splunk/src/test/java/org/apache/drill/exec/store/splunk/SplunkConnectionTest.java b/contrib/storage-splunk/src/test/java/org/apache/drill/exec/store/splunk/SplunkConnectionTest.java index c6ef9a123df..f4884ece45e 100644 --- a/contrib/storage-splunk/src/test/java/org/apache/drill/exec/store/splunk/SplunkConnectionTest.java +++ b/contrib/storage-splunk/src/test/java/org/apache/drill/exec/store/splunk/SplunkConnectionTest.java @@ -54,6 +54,7 @@ public void testConnectionFail() { SPLUNK_STORAGE_PLUGIN_CONFIG.getToken(), SPLUNK_STORAGE_PLUGIN_CONFIG.getCookie(), SPLUNK_STORAGE_PLUGIN_CONFIG.getValidateCertificates(), + SPLUNK_STORAGE_PLUGIN_CONFIG.getValidateHostname(), SPLUNK_STORAGE_PLUGIN_CONFIG.getEarliestTime(), SPLUNK_STORAGE_PLUGIN_CONFIG.getLatestTime(), null, diff --git a/contrib/storage-splunk/src/test/java/org/apache/drill/exec/store/splunk/SplunkTestSuite.java b/contrib/storage-splunk/src/test/java/org/apache/drill/exec/store/splunk/SplunkTestSuite.java index 27024b8ea19..5cd228d70ec 100644 --- a/contrib/storage-splunk/src/test/java/org/apache/drill/exec/store/splunk/SplunkTestSuite.java +++ b/contrib/storage-splunk/src/test/java/org/apache/drill/exec/store/splunk/SplunkTestSuite.java @@ -94,7 +94,7 @@ public static void initSplunk() throws Exception { SPLUNK_STORAGE_PLUGIN_CONFIG = new SplunkPluginConfig( SPLUNK_LOGIN, SPLUNK_PASS, "http", hostname, port, - null, null, null, null, false, // app, owner, token, cookie, validateCertificates + null, null, null, null, false, true, // app, owner, token, cookie, validateCertificates "1", "now", null, 4, @@ -116,7 +116,7 @@ public static void initSplunk() throws Exception { SPLUNK_STORAGE_PLUGIN_CONFIG_WITH_USER_TRANSLATION = new SplunkPluginConfig( null, null, // username, password "http", hostname, port, - null, null, null, null, false, // app, owner, token, cookie, validateCertificates + null, null, null, null, false, false, // app, owner, token, cookie, validateCertificates "1", "now", credentialsProvider, 4,