Skip to content
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

Friendly exception for cipher suite issue #2053

Merged
merged 15 commits into from
Jan 25, 2022
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,15 @@

import com.microsoft.applicationinsights.agent.internal.configuration.DefaultEndpoints;
import java.io.File;
import java.io.IOException;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLSocketFactory;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.slf4j.Logger;

Expand All @@ -49,9 +55,39 @@ public static boolean logSpecialOneTimeFriendlyException(
// e.g. wrong host address or cannot reach address due to network issues...
return false;
}

IOException ioException = getCausedByOfType(error, IOException.class);
SocketException socketException = getCausedByOfType(error, SocketException.class);
if (ioException != null || socketException != null) {
if (!alreadySeen.getAndSet(true)) {
kryalama marked this conversation as resolved.
Show resolved Hide resolved
List<String> existingCiphers = getCiphersFromJvm(logger);
if (existingCiphers.size() == 0) {
return false;
}
logger.error(getCipherFriendlyMessage(url, existingCiphers));
}
return true;
}
return false;
}

private static List<String> getCiphersFromJvm(Logger logger) {
final List<String> ciphersFromJvm = new ArrayList<>();
final SSLContext context;
try {
context = SSLContext.getDefault();
SSLSocketFactory socketFactory = context.getSocketFactory();
String[] cipherSuites = socketFactory.getSupportedCipherSuites();
for (String s : cipherSuites) {
ciphersFromJvm.add(s);
}
return ciphersFromJvm;
} catch (Exception e) {
logger.error(e.getMessage(), e);
kryalama marked this conversation as resolved.
Show resolved Hide resolved
return ciphersFromJvm;
}
}

private static <T extends Exception> T getCausedByOfType(Throwable throwable, Class<T> type) {
if (type.isInstance(throwable)) {
@SuppressWarnings("unchecked")
Expand All @@ -67,19 +103,45 @@ private static <T extends Exception> T getCausedByOfType(Throwable throwable, Cl

private static String getSslFriendlyMessage(String url) {
return FriendlyException.populateFriendlyMessage(
getSslFriendlyExceptionBanner(url),
getSslFriendlyExceptionAction(url),
"Unable to find valid certification path to requested target.",
getSslFriendlyExceptionAction(url),
getFriendlyExceptionBanner(url),
"This message is only logged the first time it occurs after startup.");
}

private static String getCipherFriendlyMessage(String url, List<String> missingCiphers) {
return FriendlyException.populateFriendlyMessage(
"Probable root cause may be : missing cipher suites which are expected by the requested target.",
getCipherFriendlyExceptionAction(url, missingCiphers),
getFriendlyExceptionBanner(url),
"This message is only logged the first time it occurs after startup.");
}

private static String getSslFriendlyExceptionBanner(String url) {
if (url.equals(DefaultEndpoints.LIVE_ENDPOINT)) {
private static String getFriendlyExceptionBanner(String url) {
if (url.contains(DefaultEndpoints.LIVE_ENDPOINT)) {
return "ApplicationInsights Java Agent failed to connect to Live metric end point.";
}
return "ApplicationInsights Java Agent failed to send telemetry data.";
}

private static String getCipherFriendlyExceptionAction(String url, List<String> missingCiphers) {
StringBuilder actionBuilder = new StringBuilder();
actionBuilder.append("The following are the cipher suites from Java runtime: ").append("\n");
if (missingCiphers.size() > 0) {
for (String missingCipher : missingCiphers) {
actionBuilder.append(missingCipher).append("\n");
}
}
actionBuilder
.append(
"Please add the required java modules to include the missing cipher suites that are expected from the target endpoint:"
kryalama marked this conversation as resolved.
Show resolved Hide resolved
+ url)
.append("\n");
actionBuilder.append(
"Learn more about handling cipher suites here: https://go.microsoft.com/fwlink/?linkid=2185426");
return actionBuilder.toString();
}

private static String getSslFriendlyExceptionAction(String url) {
String customJavaKeyStorePath = getCustomJavaKeystorePath();
if (customJavaKeyStorePath != null) {
Expand Down