Skip to content

WIP :- SSL certificate validation #207

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,21 @@ To build the documentation for the SDK, it is being automatically generated with
cd splunk
mvn javadoc:javadoc

###SSL Certificate Verification
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing space after ### for headers

SSL Certificate validation is turned ON by default in Splunk Java SDK. Set SSL Certificate as shown below.
```java
HttpService.setSSLCert(<byte[] sslCert>);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still needs the data input app to provide the cert. How do the data input app figure out which cert to provide here when communicating with the Splunk Enterprise/Cloud ?

```
Note:- For local/Non-production/any other use cases SSL Certificate validation can be disabled as shown below.
```java
HttpService.setValidateCertificates(false).
```


### Usage
#### Login using username and password
```java
import com.splunk.HttpService;
import com.splunk.Service;
import com.splunk.ServiceArgs;

Expand All @@ -129,6 +141,9 @@ public class SplunkLogin {
loginArgs.setUsername("USERNAME"); // Use your username
loginArgs.setPassword("PASSWORD"); // Use your password

//set SSL Certificate for verification
byte[] sslCert = <read Certificate file into byte array>
HttpService.setSSLCert(sslCert);
// Initialize the SDK client
service = Service.connect(loginArgs);
}
Expand All @@ -137,6 +152,7 @@ public class SplunkLogin {

#### Login using Session Token
```java
import com.splunk.HttpService;
import com.splunk.Service;
import com.splunk.ServiceArgs;

Expand All @@ -159,6 +175,9 @@ public class SplunkLogin {
loginArgs.setScheme("https");
loginArgs.setToken(String.format("Splunk %s", token));

//set SSL Certificate for verification
byte[] sslCert = <read Certificate file into byte array>
HttpService.setSSLCert(sslCert);
// Initialize the SDK client
service = Service.connect(loginArgs);
}
Expand All @@ -173,6 +192,7 @@ public class SplunkLogin {

#### Login using Authentication Token (RECOMMENDED)
```java
import com.splunk.HttpService;
import com.splunk.Service;
import com.splunk.ServiceArgs;

Expand All @@ -195,6 +215,9 @@ public class SplunkLogin {
loginArgs.setScheme("https");
loginArgs.setToken(String.format("Bearer %s", token));

//set SSL Certificate for verification
byte[] sslCert = <read Certificate file into byte array>
HttpService.setSSLCert(sslCert);
// Initialize the SDK client
service = Service.connect(loginArgs);
}
Expand All @@ -206,6 +229,7 @@ public class SplunkLogin {
import com.splunk.Job;
import com.splunk.ResultsReader;
import com.splunk.ResultsReaderXml;
import com.splunk.HttpService;
import com.splunk.Service;
import com.splunk.ServiceArgs;

Expand Down Expand Up @@ -233,6 +257,9 @@ public class SearchExample {
loginArgs.setScheme("https");
loginArgs.setToken(String.format("Bearer %s", token));

//set SSL Certificate for verification
byte[] sslCert = <read Certificate file into byte array>
HttpService.setSSLCert(sslCert);
// Initialize the SDK client
service = Service.connect(loginArgs);

Expand Down
40 changes: 31 additions & 9 deletions splunk/src/main/java/com/splunk/HttpService.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,10 @@
package com.splunk;

import javax.net.ssl.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.*;
import java.net.*;
import java.security.KeyStore;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.List;
Expand All @@ -46,6 +45,7 @@ public class HttpService {
* Default Value: TRUE
*/
protected static boolean validateCertificates = true;
protected static byte[] sslCert = null;

private static SSLSocketFactory sslSocketFactory = createSSLFactory();
private static String HTTPS_SCHEME = "https";
Expand Down Expand Up @@ -436,6 +436,11 @@ Socket open() throws IOException {
* @return The HTTP response.
*/
public ResponseMessage send(String path, RequestMessage request) {

if(HttpService.validateCertificates && HttpService.sslCert == null){
throw new RuntimeException("Set missing SSL Certificate for verification or Disable SSL verification and try again");
}

// Construct a full URL to the resource
URL url = getUrl(path);
// Create and initialize the connection object
Expand Down Expand Up @@ -566,6 +571,12 @@ public static void setValidateCertificates(boolean validateCertificate) {
}
}

public static void setSSLCert(byte[] sslCertificate) {
// update the SSL_SOCKET_FACTORY when sslCert is set
sslCert = sslCertificate;
sslSocketFactory = createSSLFactory();
}

public static SSLSocketFactory createSSLFactory() {

try {
Expand All @@ -578,12 +589,23 @@ public static SSLSocketFactory createSSLFactory() {
} else {
context = SSLContext.getDefault();
}

if (validateCertificates) {
context.init(null, null, null);
// For now this check is set as null.
// TODO: Implementation logic for validating client certificate.
} else {
if(sslCert == null){

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add spaces between if and ( also between ) and {.

// On initialising before ssCert is set, TM and KM set to null
context.init(null, null, null);
}else{

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add spaces between } and else and {

InputStream is = new ByteArrayInputStream(sslCert);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate)cf.generateCertificate(is);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this cast to X509Certificate? It looks like the method ks.setCertificateEntry("cert", cert); supports a Certificate in the signature.

TrustManagerFactory tmf = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null); // You don't need the KeyStore instance to come from a file.
ks.setCertificateEntry("cert", cert);
tmf.init(ks);
context.init(null, tmf.getTrustManagers(), null);
}
} else{

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add a space between else and {

TrustManager[] trustAll = new TrustManager[]{
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
Expand Down
18 changes: 16 additions & 2 deletions splunk/src/test/java/com/splunk/SDKTestCase.java
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,23 @@ public static Integer getJavaVersion() {
}

@BeforeClass
public static void preClassLoadActions() {
// Bypass the certification validation here.
public static void preClassLoadActions() throws IOException {
// To Bypass the certification validation.
HttpService.setValidateCertificates(false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we have separate tests:

  1. For simulating the failure of an SSL cert validation
  2. and/or when setting to true, the ability to connect to the HTTPS resource with a valid SSL certificate?


// To Set SSL Certificate use below code block
/*
InputStream sslCertificate = ResourceRoot.class.getResourceAsStream("/Certificate.pem");
ByteArrayOutputStream os = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
// read bytes from the input stream and store them in the buffer
while ((len = sslCertificate.read(buffer)) != -1)
{
os.write(buffer, 0, len);
}
HttpService.setSSLCert(os.toByteArray());
*/
}

@Before
Expand Down