Skip to content

Commit

Permalink
Allow to disable SSL checks
Browse files Browse the repository at this point in the history
  • Loading branch information
dheid committed Nov 3, 2023
1 parent f5b6bce commit 0231d55
Show file tree
Hide file tree
Showing 9 changed files with 247 additions and 49 deletions.
48 changes: 24 additions & 24 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ ij_formatter_off_tag = @formatter:off
ij_formatter_on_tag = @formatter:on
ij_formatter_tags_enabled = true
ij_smart_tabs = false
ij_visual_guides =
ij_visual_guides =
ij_wrap_on_typing = false

[*.java]
Expand Down Expand Up @@ -67,7 +67,7 @@ ij_java_blank_lines_before_package = 1
ij_java_block_brace_style = end_of_line
ij_java_block_comment_add_space = false
ij_java_block_comment_at_first_column = true
ij_java_builder_methods =
ij_java_builder_methods =
ij_java_call_parameters_new_line_after_left_paren = true
ij_java_call_parameters_right_paren_on_new_line = true
ij_java_call_parameters_wrap = on_every_item
Expand Down Expand Up @@ -105,8 +105,8 @@ ij_java_enum_constants_wrap = split_into_lines
ij_java_extends_keyword_wrap = normal
ij_java_extends_list_wrap = on_every_item
ij_java_field_annotation_wrap = split_into_lines
ij_java_field_name_prefix =
ij_java_field_name_suffix =
ij_java_field_name_prefix =
ij_java_field_name_suffix =
ij_java_finally_on_new_line = false
ij_java_for_brace_force = always
ij_java_for_statement_new_line_after_left_paren = false
Expand All @@ -115,7 +115,7 @@ ij_java_for_statement_wrap = on_every_item
ij_java_generate_final_locals = false
ij_java_generate_final_parameters = false
ij_java_if_brace_force = always
ij_java_imports_layout = $*, |, *
ij_java_imports_layout = $*,|,*
ij_java_indent_case_from_switch = true
ij_java_insert_inner_class_imports = false
ij_java_insert_override_annotation = true
Expand All @@ -140,8 +140,8 @@ ij_java_layout_static_imports_separately = true
ij_java_line_comment_add_space = false
ij_java_line_comment_add_space_on_reformat = false
ij_java_line_comment_at_first_column = true
ij_java_local_variable_name_prefix =
ij_java_local_variable_name_suffix =
ij_java_local_variable_name_prefix =
ij_java_local_variable_name_suffix =
ij_java_method_annotation_wrap = split_into_lines
ij_java_method_brace_style = end_of_line
ij_java_method_call_chain_wrap = on_every_item
Expand All @@ -154,17 +154,17 @@ ij_java_names_count_to_use_import_on_demand = 999
ij_java_new_line_after_lparen_in_annotation = true
ij_java_new_line_after_lparen_in_deconstruction_pattern = true
ij_java_new_line_after_lparen_in_record_header = true
ij_java_packages_to_use_import_on_demand =
ij_java_packages_to_use_import_on_demand =
ij_java_parameter_annotation_wrap = split_into_lines
ij_java_parameter_name_prefix =
ij_java_parameter_name_suffix =
ij_java_parameter_name_prefix =
ij_java_parameter_name_suffix =
ij_java_parentheses_expression_new_line_after_left_paren = true
ij_java_parentheses_expression_right_paren_on_new_line = true
ij_java_place_assignment_sign_on_next_line = false
ij_java_prefer_longer_names = true
ij_java_prefer_parameters_wrap = false
ij_java_record_components_wrap = on_every_item
ij_java_repeat_annotations =
ij_java_repeat_annotations =
ij_java_repeat_synchronized = true
ij_java_replace_instanceof_and_cast = false
ij_java_replace_null_check = true
Expand Down Expand Up @@ -254,13 +254,13 @@ ij_java_spaces_within_synchronized_parentheses = false
ij_java_spaces_within_try_parentheses = false
ij_java_spaces_within_while_parentheses = false
ij_java_special_else_if_treatment = true
ij_java_static_field_name_prefix =
ij_java_static_field_name_suffix =
ij_java_subclass_name_prefix =
ij_java_static_field_name_prefix =
ij_java_static_field_name_suffix =
ij_java_subclass_name_prefix =
ij_java_subclass_name_suffix = Impl
ij_java_ternary_operation_signs_on_next_line = false
ij_java_ternary_operation_wrap = normal
ij_java_test_name_prefix =
ij_java_test_name_prefix =
ij_java_test_name_suffix = Test
ij_java_throws_keyword_wrap = normal
ij_java_throws_list_wrap = on_every_item
Expand Down Expand Up @@ -397,7 +397,7 @@ ij_groovy_ginq_on_wrap_policy = 1
ij_groovy_ginq_space_after_keyword = true
ij_groovy_if_brace_force = never
ij_groovy_import_annotation_wrap = 2
ij_groovy_imports_layout = *, |, javax.**, java.**, |, $*
ij_groovy_imports_layout = *,|,javax.**,java.**,|,$*
ij_groovy_indent_case_from_switch = true
ij_groovy_indent_label_blocks = true
ij_groovy_insert_inner_class_imports = false
Expand Down Expand Up @@ -428,7 +428,7 @@ ij_groovy_method_parameters_right_paren_on_new_line = false
ij_groovy_method_parameters_wrap = off
ij_groovy_modifier_list_wrap = false
ij_groovy_names_count_to_use_import_on_demand = 3
ij_groovy_packages_to_use_import_on_demand = java.awt.*, javax.swing.*
ij_groovy_packages_to_use_import_on_demand = java.awt.*,javax.swing.*
ij_groovy_parameter_annotation_wrap = off
ij_groovy_parentheses_expression_new_line_after_left_paren = false
ij_groovy_parentheses_expression_right_paren_on_new_line = false
Expand Down Expand Up @@ -542,23 +542,23 @@ ij_json_spaces_within_brackets = false
ij_json_wrap_long_lines = false

[{*.htm,*.html,*.sht,*.shtm,*.shtml}]
ij_html_add_new_line_before_tags = body, div, p, form, h1, h2, h3
ij_html_add_new_line_before_tags = body,div,p,form,h1,h2,h3
ij_html_align_attributes = true
ij_html_align_text = false
ij_html_attribute_wrap = normal
ij_html_block_comment_add_space = false
ij_html_block_comment_at_first_column = true
ij_html_do_not_align_children_of_min_lines = 0
ij_html_do_not_break_if_inline_tags = title, h1, h2, h3, h4, h5, h6, p
ij_html_do_not_indent_children_of_tags = html, body, thead, tbody, tfoot
ij_html_do_not_break_if_inline_tags = title,h1,h2,h3,h4,h5,h6,p
ij_html_do_not_indent_children_of_tags = html,body,thead,tbody,tfoot
ij_html_enforce_quotes = false
ij_html_inline_tags = a, abbr, acronym, b, basefont, bdo, big, br, cite, cite, code, dfn, em, font, i, img, input, kbd, label, q, s, samp, select, small, span, strike, strong, sub, sup, textarea, tt, u, var
ij_html_inline_tags = a,abbr,acronym,b,basefont,bdo,big,br,cite,cite,code,dfn,em,font,i,img,input,kbd,label,q,s,samp,select,small,span,strike,strong,sub,sup,textarea,tt,u,var
ij_html_keep_blank_lines = 2
ij_html_keep_indents_on_empty_lines = false
ij_html_keep_line_breaks = true
ij_html_keep_line_breaks_in_text = true
ij_html_keep_whitespaces = false
ij_html_keep_whitespaces_inside = span, pre, textarea
ij_html_keep_whitespaces_inside = span,pre,textarea
ij_html_line_comment_at_first_column = true
ij_html_new_line_after_last_attribute = never
ij_html_new_line_before_first_attribute = never
Expand Down Expand Up @@ -603,7 +603,7 @@ ij_kotlin_field_annotation_wrap = split_into_lines
ij_kotlin_finally_on_new_line = false
ij_kotlin_if_rparen_on_new_line = false
ij_kotlin_import_nested_classes = false
ij_kotlin_imports_layout = *, java.**, javax.**, kotlin.**, ^
ij_kotlin_imports_layout = *,java.**,javax.**,kotlin.**,^
ij_kotlin_insert_whitespaces_in_simple_one_line_method = true
ij_kotlin_keep_blank_lines_before_right_brace = 2
ij_kotlin_keep_blank_lines_in_code = 2
Expand All @@ -623,7 +623,7 @@ ij_kotlin_method_parameters_right_paren_on_new_line = false
ij_kotlin_method_parameters_wrap = off
ij_kotlin_name_count_to_use_star_import = 5
ij_kotlin_name_count_to_use_star_import_for_members = 3
ij_kotlin_packages_to_use_import_on_demand = java.util.*, kotlinx.android.synthetic.**, io.ktor.**
ij_kotlin_packages_to_use_import_on_demand = java.util.*,kotlinx.android.synthetic.**,io.ktor.**
ij_kotlin_parameter_annotation_wrap = off
ij_kotlin_space_after_comma = true
ij_kotlin_space_after_extend_colon = true
Expand Down
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Features include:
* Supports custom dimensions and custom variables
* Includes tracking parameters for campaigns, events, downloads, outlinks, site search, devices, visiors
* Supports Java 8 and higher
* Allows you to skip SSL certificate validation (not recommended for production)
* Contains nearly no dependencies
* Allows asynchronous requests
* Supports Matomo 4 and 5
Expand All @@ -29,7 +30,7 @@ Further information on Matomo and Matomo HTTP tracking:

* [Matomo PHP Tracker](https://github.com/matomo-org/matomo-php-tracker)
* [Matomo Tracking HTTP API](https://developer.matomo.org/api-reference/tracking-api)
* [Introducting the Matomo Java Tracker](https://matomo.org/blog/2015/11/introducing-piwik-java-tracker/)
* [Introducing the Matomo Java Tracker](https://matomo.org/blog/2015/11/introducing-piwik-java-tracker/)
* [Tracking API User Guide](https://matomo.org/guide/apis/tracking-api/)
* [Matomo Developer](https://developer.matomo.org/)
* [The Matomo project](https://matomo.org/)
Expand Down Expand Up @@ -222,10 +223,14 @@ The Matomo Tracker currently supports the following builder methods:
* `.proxyHost(...)` The hostname or IP address of an optional HTTP proxy. `proxyPort` must be
configured as well
* `.proxyPort(...)` The port of an HTTP proxy. `proxyHost` must be configured as well.
* `.proxyUserName(...)` If the HTTP proxy requires a user name for basic authentication, it can be
* `.proxyUserName(...)` If the HTTP proxy requires a username for basic authentication, it can be
configured with this method. Proxy host, port and password must also be set.
* `.proxyPassword(...)` The corresponding password for the basic auth proxy user. The proxy host,
port and user name must be set as well.
port and username must be set as well.
* `.disableSslCertValidation(...)` If set to true, the SSL certificate of the Matomo server will not be validated. This
should only be used for testing purposes. Default: false
* `.disableSslHostVerification(...)` If set to true, the SSL host of the Matomo server will not be validated. This should
only be used for testing purposes. Default: false

To send a single request synchronously via GET, call

Expand Down
77 changes: 61 additions & 16 deletions src/main/java/org/matomo/java/tracking/Sender.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,30 @@
import java.net.URI;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@RequiredArgsConstructor
class Sender {

private static final TrustManager[] TRUST_ALL_MANAGERS = new TrustManager[] {
new TrustingX509TrustManager()
};
public static final TrustingHostnameVerifier TRUSTING_HOSTNAME_VERIFIER =
new TrustingHostnameVerifier();

private final TrackerConfiguration trackerConfiguration;

private final QueryCreator queryCreator;
Expand Down Expand Up @@ -87,28 +97,64 @@ void sendSingle(
}

private HttpURLConnection openConnection(URL url) {
HttpURLConnection connection;
try {
if (isEmpty(trackerConfiguration.getProxyHost())
|| trackerConfiguration.getProxyPort() <= 0) {
log.debug("Proxy host or proxy port not configured. Will create connection without proxy");
return (HttpURLConnection) url.openConnection();
}
InetSocketAddress proxyAddress = new InetSocketAddress(
trackerConfiguration.getProxyHost(),
trackerConfiguration.getProxyPort()
);
Proxy proxy = new Proxy(Proxy.Type.HTTP, proxyAddress);
if (!isEmpty(trackerConfiguration.getProxyUserName())
&& !isEmpty(trackerConfiguration.getProxyPassword())) {
Authenticator.setDefault(new ProxyAuthenticator(
trackerConfiguration.getProxyUserName(),
trackerConfiguration.getProxyPassword()
));
connection = (HttpURLConnection) url.openConnection();
} else {
connection = openProxiedConnection(url);
}
return (HttpURLConnection) url.openConnection(proxy);
} catch (IOException e) {
throw new MatomoException("Could not open connection", e);
}
if (connection instanceof HttpsURLConnection) {
applySslConfiguration((HttpsURLConnection) connection);
}
return connection;
}

private void applySslConfiguration(
@NonNull
HttpsURLConnection connection
) {
requireNonNull(connection, "Connection must not be null");
if (trackerConfiguration.isDisableSslCertValidation()) {
try {
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, TRUST_ALL_MANAGERS, new SecureRandom());
connection.setSSLSocketFactory(sslContext.getSocketFactory());
} catch (Exception e) {
throw new MatomoException("Could not disable SSL certification validation", e);
}
}
if (trackerConfiguration.isDisableSslHostVerification()) {
connection.setHostnameVerifier(TRUSTING_HOSTNAME_VERIFIER);
}
}

private HttpURLConnection openProxiedConnection(@NonNull URL url) throws IOException {
requireNonNull(url, "URL must not be null");
requireNonNull(trackerConfiguration.getProxyHost(), "Proxy host must not be null");
if (trackerConfiguration.getProxyPort() <= 0) {
throw new IllegalArgumentException("Proxy port must be configured");
}
InetSocketAddress proxyAddress = new InetSocketAddress(trackerConfiguration.getProxyHost(),
trackerConfiguration.getProxyPort()
);
Proxy proxy = new Proxy(Proxy.Type.HTTP, proxyAddress);
if (!isEmpty(trackerConfiguration.getProxyUserName())
&& !isEmpty(trackerConfiguration.getProxyPassword())) {
Authenticator.setDefault(new ProxyAuthenticator(trackerConfiguration.getProxyUserName(),
trackerConfiguration.getProxyPassword()
));
}
log.debug("Using proxy {} on port {}",
trackerConfiguration.getProxyHost(),
trackerConfiguration.getProxyPort()
);
return (HttpURLConnection) url.openConnection(proxy);
}

private void configureAgentsAndTimeouts(HttpURLConnection connection) {
Expand Down Expand Up @@ -168,8 +214,7 @@ private void sendBulk(
}
preparePostConnection(connection);
configureAgentsAndTimeouts(connection);
log.debug(
"Sending bulk request using URI {} asynchronously",
log.debug("Sending bulk request using URI {} asynchronously",
trackerConfiguration.getApiEndpoint()
);
OutputStream outputStream = null;
Expand Down
23 changes: 22 additions & 1 deletion src/main/java/org/matomo/java/tracking/TrackerConfiguration.java
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,31 @@ public class TrackerConfiguration {
@NonNull String userAgent = "MatomoJavaClient";

/**
* Logs if the Matomo Tracking API endpoint responds with an erroneous HTTP code.
* Logs if the Matomo Tracking API endpoint responds with an erroneous HTTP code. Defaults to
* false.
*/
boolean logFailedTracking;

/**
* Disables SSL certificate validation. This is useful for testing with self-signed certificates.
* Do not use in production environments. Defaults to false.
*
* <p>Attention: This slows down performance
* @see #disableSslHostVerification
*/
boolean disableSslCertValidation;

/**
* Disables SSL host verification. This is useful for testing with self-signed certificates. Do
* not use in production environments. Defaults to false.
*
* <p>Attention: This slows down performance
*
* @see #disableSslCertValidation
*/
boolean disableSslHostVerification;

/**
* Validates the auth token. The auth token must be exactly 32 characters long.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.matomo.java.tracking;

import edu.umd.cs.findbugs.annotations.Nullable;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;

class TrustingHostnameVerifier implements HostnameVerifier {

@Override
public boolean verify(
@Nullable
String hostname,
@Nullable
SSLSession session
) {
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.matomo.java.tracking;

import edu.umd.cs.findbugs.annotations.Nullable;
import java.security.cert.X509Certificate;
import javax.net.ssl.X509TrustManager;

class TrustingX509TrustManager implements X509TrustManager {

@Override
@Nullable
public X509Certificate[] getAcceptedIssuers() {
return null;
}

@Override
public void checkClientTrusted(
@Nullable X509Certificate[] chain, @Nullable String authType
) {
// no operation
}

@Override
public void checkServerTrusted(
@Nullable X509Certificate[] chain, @Nullable String authType
) {
// no operation
}
}
Loading

0 comments on commit 0231d55

Please sign in to comment.