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 May 9, 2018
1 parent 65b8c64 commit 23b7a9b
Show file tree
Hide file tree
Showing 6 changed files with 272 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
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.TLSVersion;
import com.snowplowanalytics.snowplow.tracker.payload.Payload;
import com.snowplowanalytics.snowplow.tracker.payload.TrackerPayload;
import com.snowplowanalytics.snowplow.tracker.storage.EventStore;
Expand All @@ -38,6 +39,7 @@

import java.io.IOException;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.LinkedList;
import java.util.concurrent.TimeUnit;

Expand Down Expand Up @@ -498,6 +500,7 @@ public Emitter getEmitter(String uri, HttpMethod method, BufferOption option, Re
.byteLimitGet(20000)
.byteLimitPost(25000)
.timeUnit(TimeUnit.SECONDS)
.tls(EnumSet.of(TLSVersion.TLSv1_2))
.build();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* 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 android.test.AndroidTestCase;

import java.util.Arrays;
import java.util.EnumSet;

public class TLSArgumentsTest extends AndroidTestCase {
public void testEnumStringConversion() {
EnumSet<TLSVersion> versions = EnumSet.of(TLSVersion.TLSv1_2, TLSVersion.TLSv1_1);
TLSArguments arguments = new TLSArguments(versions);
String[] stringVersions = arguments.getVersions();
assertTrue(Arrays.asList(stringVersions).contains("TLSv1.2"));
assertTrue(Arrays.asList(stringVersions).contains("TLSv1.1"));
}
}
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.TLSVersion;
import com.snowplowanalytics.snowplow.tracker.payload.Payload;
import com.snowplowanalytics.snowplow.tracker.storage.EventStore;
import com.snowplowanalytics.snowplow.tracker.utils.Logger;
Expand All @@ -42,6 +44,7 @@
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.EnumSet;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
Expand All @@ -68,6 +71,7 @@ public class Emitter {
private HttpMethod httpMethod;
private BufferOption bufferOption;
private RequestSecurity requestSecurity;
private EnumSet<TLSVersion> tlsVersions;
private String uri;
private int emitterTick;
private int emptyLimit;
Expand All @@ -92,6 +96,7 @@ public static class EmitterBuilder {
HttpMethod httpMethod = HttpMethod.POST; // Optional
BufferOption bufferOption = BufferOption.DefaultGroup; // Optional
RequestSecurity requestSecurity = RequestSecurity.HTTP; // Optional
EnumSet<TLSVersion> tlsVersions = EnumSet.of(TLSVersion.TLSv1_2); // Optional
int emitterTick = 5; // Optional
int sendLimit = 250; // Optional
int emptyLimit = 5; // Optional
Expand Down Expand Up @@ -135,6 +140,24 @@ public EmitterBuilder security(RequestSecurity requestSecurity) {
return this;
}

/**
* @param version the TLS version allowed for requests
* @return itself
*/
public EmitterBuilder tls(TLSVersion version) {
this.tlsVersions = EnumSet.of(version);
return this;
}

/**
* @param versions the TLS versions allowed for requests
* @return itself
*/
public EmitterBuilder tls(EnumSet<TLSVersion> versions) {
this.tlsVersions = versions;
return this;
}

/**
* @param requestCallback Request callback function
* @return itself
Expand Down Expand Up @@ -222,6 +245,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 +255,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 +771,13 @@ public RequestSecurity getRequestSecurity() {
return this.requestSecurity;
}

/**
* @return the TLS versions accepted for the emitter
*/
public EnumSet<TLSVersion> getTlsVersions() {
return this.tlsVersions;
}

/**
* @return the emitter tick
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* 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 java.util.EnumSet;
import java.util.HashSet;

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;
private EnumSet<TLSVersion> tlsVersions = null;

/**
* Builds an object to store arguments to pass to TLS connection configuration.
*
* @param versions Accepted TLS versions for connections
*/
public TLSArguments(EnumSet<TLSVersion> versions) {
this.tlsVersions = 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(this.getVersions());
} 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;
}

/**
* @return TLS versions
*/
public String[] getVersions() {
String[] acceptedVersions = new String[tlsVersions.size()];
int i = 0;
for (TLSVersion version : tlsVersions) {
acceptedVersions[i] = version.toString();
i++;
}
return acceptedVersions;
}
}
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;

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,26 @@
/*
* 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;

public enum TLSVersion {
/**
* Accepted versions of TLS to be used by emitter.
*/
TLSv1_1,
TLSv1_2;

public String toString() {
return name().replace("_", ".");
}
}

0 comments on commit 23b7a9b

Please sign in to comment.