Skip to content

Commit

Permalink
Add ability to specify TLS protocols to use for emitting events (close
Browse files Browse the repository at this point in the history
  • Loading branch information
mhadam committed Apr 19, 2018
1 parent 65b8c64 commit 28e2cee
Show file tree
Hide file tree
Showing 5 changed files with 250 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,7 @@ public Emitter getEmitter(String uri, HttpMethod method, BufferOption option, Re
.byteLimitGet(20000)
.byteLimitPost(25000)
.timeUnit(TimeUnit.SECONDS)
.tls("TLSv1.2")
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import com.snowplowanalytics.snowplow.tracker.emitter.ReadyRequest;
import com.snowplowanalytics.snowplow.tracker.emitter.RequestCallback;
import com.snowplowanalytics.snowplow.tracker.emitter.RequestSecurity;
import com.snowplowanalytics.snowplow.tracker.emitter.TLSArguments;
import com.snowplowanalytics.snowplow.tracker.emitter.TLSVersionValidator;
import com.snowplowanalytics.snowplow.tracker.payload.Payload;
import com.snowplowanalytics.snowplow.tracker.storage.EventStore;
import com.snowplowanalytics.snowplow.tracker.utils.Logger;
Expand Down Expand Up @@ -68,6 +70,7 @@ public class Emitter {
private HttpMethod httpMethod;
private BufferOption bufferOption;
private RequestSecurity requestSecurity;
private String[] tlsVersions;
private String uri;
private int emitterTick;
private int emptyLimit;
Expand All @@ -92,6 +95,7 @@ public static class EmitterBuilder {
HttpMethod httpMethod = HttpMethod.POST; // Optional
BufferOption bufferOption = BufferOption.DefaultGroup; // Optional
RequestSecurity requestSecurity = RequestSecurity.HTTP; // Optional
String[] tlsVersions = new String[]{"TLSv1.2"}; // Optional
int emitterTick = 5; // Optional
int sendLimit = 250; // Optional
int emptyLimit = 5; // Optional
Expand Down Expand Up @@ -135,6 +139,26 @@ public EmitterBuilder security(RequestSecurity requestSecurity) {
return this;
}

/**
* @param version the TLS version allowed for requests
* @return itself
*/
public EmitterBuilder tls(String version) {
TLSVersionValidator versionValidator = new TLSVersionValidator(version);
this.tlsVersions = versionValidator.getVersions();
return this;
}

/**
* @param versions the TLS versions allowed for requests
* @return itself
*/
public EmitterBuilder tls(String[] versions) {
TLSVersionValidator versionValidator = new TLSVersionValidator(versions);
this.tlsVersions = versionValidator.getVersions();
return this;
}

/**
* @param requestCallback Request callback function
* @return itself
Expand Down Expand Up @@ -222,6 +246,7 @@ private Emitter(EmitterBuilder builder) {
this.context = builder.context;
this.bufferOption = builder.bufferOption;
this.requestSecurity = builder.requestSecurity;
this.tlsVersions = builder.tlsVersions;
this.emitterTick = builder.emitterTick;
this.emptyLimit = builder.emptyLimit;
this.sendLimit = builder.sendLimit;
Expand All @@ -231,12 +256,15 @@ private Emitter(EmitterBuilder builder) {
this.timeUnit = builder.timeUnit;
this.eventStore = new EventStore(this.context, this.sendLimit);

TLSArguments tlsArguments = new TLSArguments(this.tlsVersions);
buildEmitterUri();

client = new OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS)
.build();
.sslSocketFactory(tlsArguments.getSslSocketFactory(),
tlsArguments.getTrustManager())
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS)
.build();

Logger.v(TAG, "Emitter created successfully!");
}
Expand Down Expand Up @@ -744,6 +772,13 @@ public RequestSecurity getRequestSecurity() {
return this.requestSecurity;
}

/**
* @return the TLS versions accepted for the emitter
*/
public String[] getTlsVersions() {
return this.tlsVersions;
}

/**
* @return the emitter tick
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright (c) 2015-2018 Snowplow Analytics Ltd. All rights reserved.
*
* This program is licensed to you under the Apache License Version 2.0,
* and you may not use this file except in compliance with the Apache License Version 2.0.
* You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the Apache License Version 2.0 is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
*/

package com.snowplowanalytics.snowplow.tracker.emitter;

import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

import okhttp3.TlsVersion;

public class TLSArguments {
private X509TrustManager trustManager = null;
private SSLSocketFactory sslSocketFactory = null;

/**
* Builds an object to store arguments to pass to TLS connection configuration.
*
* @param versions Accepted TLS versions for connections
*/
public TLSArguments(String[] versions) {
try {
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init((KeyStore) null);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
throw new IllegalStateException("Unexpected default trust managers:"
+ Arrays.toString(trustManagers));
}
this.trustManager = (X509TrustManager) trustManagers[0];

this.sslSocketFactory = new TLSSocketFactory(versions);
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
this.trustManager = trustManager;
this.sslSocketFactory = sslSocketFactory;
}

/**
* @return the trust manager argument
*/
public X509TrustManager getTrustManager() {
return this.trustManager;
}

/**
* @return the ssl socket factory argument
*/
public SSLSocketFactory getSslSocketFactory() {
return this.sslSocketFactory;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Copyright (c) 2015-2018 Snowplow Analytics Ltd. All rights reserved.
*
* This program is licensed to you under the Apache License Version 2.0,
* and you may not use this file except in compliance with the Apache License Version 2.0.
* You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the Apache License Version 2.0 is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
*/

package com.snowplowanalytics.snowplow.tracker.emitter;

import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

public class TLSSocketFactory extends SSLSocketFactory {

private SSLSocketFactory internalSSLSocketFactory;
private String[] versions = new String[]{"TLSv1.2"};

public TLSSocketFactory(String[] versions) throws KeyManagementException, NoSuchAlgorithmException {
this.versions = versions;
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, null, null);
internalSSLSocketFactory = context.getSocketFactory();
}

@Override
public String[] getDefaultCipherSuites() {
return internalSSLSocketFactory.getDefaultCipherSuites();
}

@Override
public String[] getSupportedCipherSuites() {
return internalSSLSocketFactory.getSupportedCipherSuites();
}

@Override
public Socket createSocket() throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket());
}

@Override
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose));
}

@Override
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
}

@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port, localHost, localPort));
}

@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
}

@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort));
}

private Socket enableTLSOnSocket(Socket socket) {
if(socket != null && (socket instanceof SSLSocket)) {
((SSLSocket) socket).setEnabledProtocols(this.versions);
}
return socket;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright (c) 2015-2017 Snowplow Analytics Ltd. All rights reserved.
*
* This program is licensed to you under the Apache License Version 2.0,
* and you may not use this file except in compliance with the Apache License Version 2.0.
* You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the Apache License Version 2.0 is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
*/

package com.snowplowanalytics.snowplow.tracker.emitter;

import java.util.Set;
import java.util.HashSet;

public class TLSVersionValidator {
private Set<String> versions = new HashSet<>();

/**
* Builds an object to only allow valid version values
*
* @param versions Versions allowed in TLS connection
*/
public TLSVersionValidator(String[] versions) {
for (String version : versions) {
if (version.equalsIgnoreCase("TLSv1.2")) {
this.versions.add("TLSv1.2");
} else if (version.equalsIgnoreCase("TLSv1.1")) {
this.versions.add("TLSv1.1");
}
}
}

public TLSVersionValidator(String version) {
if (version.equalsIgnoreCase("TLSv1.2")) {
this.versions.add("TLSv1.2");
} else if (version.equalsIgnoreCase("TLSv1.1")) {
this.versions.add("TLSv1.1");
}
}

/**
* @return Version of TLS connection
*/
public String[] getVersions() {
return versions.toArray(new String[versions.size()]);
}
}

0 comments on commit 28e2cee

Please sign in to comment.