summaryrefslogtreecommitdiffstats
path: root/jdisc_http_service
diff options
context:
space:
mode:
authorBjørn Christian Seime <bjorncs@verizonmedia.com>2021-02-19 11:19:05 +0100
committerBjørn Christian Seime <bjorncs@verizonmedia.com>2021-02-19 11:19:05 +0100
commit834df21bfa4ec238e62ecd8788358db7ac04983a (patch)
tree5fc4c6c0050a96a4dd6cc45e9040194cc9fa6f35 /jdisc_http_service
parent9d9c5fd49909b7906a22a4f092037652c126751b (diff)
List complete exception chain for ssl handshake failure in connection log
Diffstat (limited to 'jdisc_http_service')
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/container/logging/ConnectionLogEntry.java55
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/container/logging/JsonConnectionLogWriter.java21
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyConnectionLogger.java27
-rw-r--r--jdisc_http_service/src/test/java/com/yahoo/container/logging/JsonConnectionLogWriterTest.java12
-rw-r--r--jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java29
5 files changed, 89 insertions, 55 deletions
diff --git a/jdisc_http_service/src/main/java/com/yahoo/container/logging/ConnectionLogEntry.java b/jdisc_http_service/src/main/java/com/yahoo/container/logging/ConnectionLogEntry.java
index a6b800a9279..6afe3b74329 100644
--- a/jdisc_http_service/src/main/java/com/yahoo/container/logging/ConnectionLogEntry.java
+++ b/jdisc_http_service/src/main/java/com/yahoo/container/logging/ConnectionLogEntry.java
@@ -3,6 +3,7 @@
package com.yahoo.container.logging;
import java.time.Instant;
+import java.util.List;
import java.util.Optional;
import java.util.UUID;
@@ -31,9 +32,7 @@ public class ConnectionLogEntry {
private final Instant sslPeerNotBefore;
private final Instant sslPeerNotAfter;
private final String sslSniServerName;
- private final String sslHandshakeFailureException;
- private final String sslHandshakeFailureMessage;
- private final String sslHandshakeFailureType;
+ private final SslHandshakeFailure sslHandshakeFailure;
private ConnectionLogEntry(Builder builder) {
@@ -57,9 +56,7 @@ public class ConnectionLogEntry {
this.sslPeerNotBefore = builder.sslPeerNotBefore;
this.sslPeerNotAfter = builder.sslPeerNotAfter;
this.sslSniServerName = builder.sslSniServerName;
- this.sslHandshakeFailureException = builder.sslHandshakeFailureException;
- this.sslHandshakeFailureMessage = builder.sslHandshakeFailureMessage;
- this.sslHandshakeFailureType = builder.sslHandshakeFailureType;
+ this.sslHandshakeFailure = builder.sslHandshakeFailure;
}
public static Builder builder(UUID id, Instant timestamp) {
@@ -86,9 +83,33 @@ public class ConnectionLogEntry {
public Optional<Instant> sslPeerNotBefore() { return Optional.ofNullable(sslPeerNotBefore); }
public Optional<Instant> sslPeerNotAfter() { return Optional.ofNullable(sslPeerNotAfter); }
public Optional<String> sslSniServerName() { return Optional.ofNullable(sslSniServerName); }
- public Optional<String> sslHandshakeFailureException() { return Optional.ofNullable(sslHandshakeFailureException); }
- public Optional<String> sslHandshakeFailureMessage() { return Optional.ofNullable(sslHandshakeFailureMessage); }
- public Optional<String> sslHandshakeFailureType() { return Optional.ofNullable(sslHandshakeFailureType); }
+ public Optional<SslHandshakeFailure> sslHandshakeFailure() { return Optional.ofNullable(sslHandshakeFailure); }
+
+ public static class SslHandshakeFailure {
+ private final String type;
+ private final List<ExceptionEntry> exceptionChain;
+
+ public SslHandshakeFailure(String type, List<ExceptionEntry> exceptionChain) {
+ this.type = type;
+ this.exceptionChain = List.copyOf(exceptionChain);
+ }
+
+ public String type() { return type; }
+ public List<ExceptionEntry> exceptionChain() { return exceptionChain; }
+
+ public static class ExceptionEntry {
+ private final String name;
+ private final String message;
+
+ public ExceptionEntry(String name, String message) {
+ this.name = name;
+ this.message = message;
+ }
+
+ public String name() { return name; }
+ public String message() { return message; }
+ }
+ }
public static class Builder {
private final UUID id;
@@ -111,9 +132,7 @@ public class ConnectionLogEntry {
private Instant sslPeerNotBefore;
private Instant sslPeerNotAfter;
private String sslSniServerName;
- private String sslHandshakeFailureException;
- private String sslHandshakeFailureMessage;
- private String sslHandshakeFailureType;
+ private SslHandshakeFailure sslHandshakeFailure;
Builder(UUID id, Instant timestamp) {
@@ -194,16 +213,8 @@ public class ConnectionLogEntry {
this.sslSniServerName = sslSniServerName;
return this;
}
- public Builder withSslHandshakeFailureException(String exception) {
- this.sslHandshakeFailureException = exception;
- return this;
- }
- public Builder withSslHandshakeFailureMessage(String message) {
- this.sslHandshakeFailureMessage = message;
- return this;
- }
- public Builder withSslHandshakeFailureType(String type) {
- this.sslHandshakeFailureType = type;
+ public Builder withSslHandshakeFailure(SslHandshakeFailure sslHandshakeFailure) {
+ this.sslHandshakeFailure = sslHandshakeFailure;
return this;
}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/container/logging/JsonConnectionLogWriter.java b/jdisc_http_service/src/main/java/com/yahoo/container/logging/JsonConnectionLogWriter.java
index 394f87c07cc..158d2ec4ea6 100644
--- a/jdisc_http_service/src/main/java/com/yahoo/container/logging/JsonConnectionLogWriter.java
+++ b/jdisc_http_service/src/main/java/com/yahoo/container/logging/JsonConnectionLogWriter.java
@@ -5,6 +5,7 @@ import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.yahoo.container.logging.ConnectionLogEntry.SslHandshakeFailure.ExceptionEntry;
import java.io.IOException;
import java.io.OutputStream;
@@ -46,13 +47,11 @@ class JsonConnectionLogWriter implements LogWriter<ConnectionLogEntry> {
Instant sslPeerNotBefore = unwrap(record.sslPeerNotBefore());
Instant sslPeerNotAfter = unwrap(record.sslPeerNotAfter());
String sslSniServerName = unwrap(record.sslSniServerName());
- String sslHandshakeFailureException = unwrap(record.sslHandshakeFailureException());
- String sslHandshakeFailureMessage = unwrap(record.sslHandshakeFailureMessage());
- String sslHandshakeFailureType = unwrap(record.sslHandshakeFailureType());
+ ConnectionLogEntry.SslHandshakeFailure sslHandshakeFailure = unwrap(record.sslHandshakeFailure());
if (isAnyValuePresent(
sslProtocol, sslSessionId, sslCipherSuite, sslPeerSubject, sslPeerNotBefore, sslPeerNotAfter,
- sslSniServerName, sslHandshakeFailureException, sslHandshakeFailureMessage, sslHandshakeFailureType)) {
+ sslSniServerName, sslHandshakeFailure)) {
generator.writeObjectFieldStart("ssl");
writeOptionalString(generator, "protocol", sslProtocol);
@@ -63,11 +62,17 @@ class JsonConnectionLogWriter implements LogWriter<ConnectionLogEntry> {
writeOptionalTimestamp(generator, "peerNotAfter", sslPeerNotAfter);
writeOptionalString(generator, "sniServerName", sslSniServerName);
- if (isAnyValuePresent(sslHandshakeFailureException, sslHandshakeFailureMessage, sslHandshakeFailureType)) {
+ if (sslHandshakeFailure != null) {
generator.writeObjectFieldStart("handshake-failure");
- writeOptionalString(generator, "exception", sslHandshakeFailureException);
- writeOptionalString(generator, "message", sslHandshakeFailureMessage);
- writeOptionalString(generator, "type", sslHandshakeFailureType);
+ generator.writeArrayFieldStart("exception");
+ for (ExceptionEntry entry : sslHandshakeFailure.exceptionChain()) {
+ generator.writeStartObject();
+ generator.writeStringField("cause", entry.name());
+ generator.writeStringField("message", entry.message());
+ generator.writeEndObject();
+ }
+ generator.writeEndArray();
+ generator.writeStringField("type", sslHandshakeFailure.type());
generator.writeEndObject();
}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyConnectionLogger.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyConnectionLogger.java
index cb3a5d046d8..34a91a3bbb4 100644
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyConnectionLogger.java
+++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyConnectionLogger.java
@@ -3,6 +3,7 @@ package com.yahoo.jdisc.http.server.jetty;
import com.yahoo.container.logging.ConnectionLog;
import com.yahoo.container.logging.ConnectionLogEntry;
+import com.yahoo.container.logging.ConnectionLogEntry.SslHandshakeFailure.ExceptionEntry;
import com.yahoo.io.HexDump;
import com.yahoo.jdisc.http.ServerConfig;
import org.eclipse.jetty.io.Connection;
@@ -27,6 +28,7 @@ import javax.net.ssl.StandardConstants;
import java.net.InetSocketAddress;
import java.security.cert.X509Certificate;
import java.time.Instant;
+import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
@@ -222,9 +224,7 @@ class JettyConnectionLogger extends AbstractLifeCycle implements Connection.List
private Date sslPeerNotBefore;
private Date sslPeerNotAfter;
private List<SNIServerName> sslSniServerNames;
- private String sslHandshakeFailureException;
- private String sslHandshakeFailureMessage;
- private String sslHandshakeFailureType;
+ private SSLHandshakeException sslHandshakeException;
private ConnectionInfo(UUID uuid, long createdAt, InetSocketAddress localAddress, InetSocketAddress peerAddress) {
this.uuid = uuid;
@@ -284,11 +284,7 @@ class JettyConnectionLogger extends AbstractLifeCycle implements Connection.List
}
synchronized ConnectionInfo setSslHandshakeFailure(SSLHandshakeException exception) {
- this.sslHandshakeFailureException = exception.getClass().getName();
- this.sslHandshakeFailureMessage = exception.getMessage();
- this.sslHandshakeFailureType = SslHandshakeFailure.fromSslHandshakeException(exception)
- .map(SslHandshakeFailure::failureType)
- .orElse("UNKNOWN");
+ this.sslHandshakeException = exception;
return this;
}
@@ -338,10 +334,17 @@ class JettyConnectionLogger extends AbstractLifeCycle implements Connection.List
.withSslPeerNotAfter(sslPeerNotAfter.toInstant())
.withSslPeerNotBefore(sslPeerNotBefore.toInstant());
}
- if (sslHandshakeFailureException != null && sslHandshakeFailureMessage != null && sslHandshakeFailureType != null) {
- builder.withSslHandshakeFailureException(sslHandshakeFailureException)
- .withSslHandshakeFailureMessage(sslHandshakeFailureMessage)
- .withSslHandshakeFailureType(sslHandshakeFailureType);
+ if (sslHandshakeException != null) {
+ List<ExceptionEntry> exceptionChain = new ArrayList<>();
+ Throwable cause = sslHandshakeException;
+ while (cause != null) {
+ exceptionChain.add(new ExceptionEntry(cause.getClass().getName(), cause.getMessage()));
+ cause = cause.getCause();
+ }
+ String type = SslHandshakeFailure.fromSslHandshakeException(sslHandshakeException)
+ .map(SslHandshakeFailure::failureType)
+ .orElse("UNKNOWN");
+ builder.withSslHandshakeFailure(new ConnectionLogEntry.SslHandshakeFailure(type, exceptionChain));
}
return builder.build();
}
diff --git a/jdisc_http_service/src/test/java/com/yahoo/container/logging/JsonConnectionLogWriterTest.java b/jdisc_http_service/src/test/java/com/yahoo/container/logging/JsonConnectionLogWriterTest.java
index b8978fe489c..8944ae9d288 100644
--- a/jdisc_http_service/src/test/java/com/yahoo/container/logging/JsonConnectionLogWriterTest.java
+++ b/jdisc_http_service/src/test/java/com/yahoo/container/logging/JsonConnectionLogWriterTest.java
@@ -1,6 +1,7 @@
package com.yahoo.container.logging;// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
import com.yahoo.test.json.JsonTestHelper;
+import com.yahoo.vespa.jdk8compat.List;
import org.junit.jupiter.api.Test;
import java.io.ByteArrayOutputStream;
@@ -20,12 +21,19 @@ class JsonConnectionLogWriterTest {
var instant = Instant.parse("2021-01-13T12:12:12Z");
ConnectionLogEntry entry = ConnectionLogEntry.builder(id, instant)
.withPeerPort(1234)
+ .withSslHandshakeFailure(new ConnectionLogEntry.SslHandshakeFailure("UNKNOWN",
+ List.of(
+ new ConnectionLogEntry.SslHandshakeFailure.ExceptionEntry("javax.net.ssl.SSLHandshakeException", "message"),
+ new ConnectionLogEntry.SslHandshakeFailure.ExceptionEntry("java.io.IOException", "cause message"))))
.build();
String expectedJson = "{" +
"\"id\":\""+id.toString()+"\"," +
"\"timestamp\":\"2021-01-13T12:12:12Z\"," +
- "\"peerPort\":1234" +
- "}";
+ "\"peerPort\":1234," +
+ "\"ssl\":{\"handshake-failure\":{\"exception\":[" +
+ "{\"cause\":\"javax.net.ssl.SSLHandshakeException\",\"message\":\"message\"}," +
+ "{\"cause\":\"java.io.IOException\",\"message\":\"cause message\"}" +
+ "],\"type\":\"UNKNOWN\"}}}";
JsonConnectionLogWriter writer = new JsonConnectionLogWriter();
ByteArrayOutputStream out = new ByteArrayOutputStream();
diff --git a/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java b/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java
index 0a4990ff101..c6ed4d42c9b 100644
--- a/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java
+++ b/jdisc_http_service/src/test/java/com/yahoo/jdisc/http/server/jetty/HttpServerTest.java
@@ -5,6 +5,7 @@ import com.google.inject.AbstractModule;
import com.google.inject.Module;
import com.yahoo.container.logging.ConnectionLog;
import com.yahoo.container.logging.ConnectionLogEntry;
+import com.yahoo.container.logging.ConnectionLogEntry.SslHandshakeFailure.ExceptionEntry;
import com.yahoo.container.logging.RequestLog;
import com.yahoo.container.logging.RequestLogEntry;
import com.yahoo.jdisc.References;
@@ -647,9 +648,8 @@ public class HttpServerTest {
.add(MetricDefinitions.SSL_HANDSHAKE_FAILURE_MISSING_CLIENT_CERT, 1L, MetricConsumerMock.STATIC_CONTEXT);
assertTrue(driver.close());
Assertions.assertThat(connectionLog.logEntries()).hasSize(1);
- ConnectionLogEntry logEntry = connectionLog.logEntries().get(0);
- Assertions.assertThat(logEntry.sslHandshakeFailureException()).hasValue(SSLHandshakeException.class.getName());
- Assertions.assertThat(logEntry.sslHandshakeFailureType()).hasValue(SslHandshakeFailure.MISSING_CLIENT_CERT.failureType());
+ assertSslHandshakeFailurePresent(
+ connectionLog.logEntries().get(0), SSLHandshakeException.class, SslHandshakeFailure.MISSING_CLIENT_CERT.failureType());
}
@Test
@@ -672,9 +672,8 @@ public class HttpServerTest {
.add(MetricDefinitions.SSL_HANDSHAKE_FAILURE_INCOMPATIBLE_PROTOCOLS, 1L, MetricConsumerMock.STATIC_CONTEXT);
assertTrue(driver.close());
Assertions.assertThat(connectionLog.logEntries()).hasSize(1);
- ConnectionLogEntry logEntry = connectionLog.logEntries().get(0);
- Assertions.assertThat(logEntry.sslHandshakeFailureException()).hasValue(SSLHandshakeException.class.getName());
- Assertions.assertThat(logEntry.sslHandshakeFailureType()).hasValue(SslHandshakeFailure.INCOMPATIBLE_PROTOCOLS.failureType());
+ assertSslHandshakeFailurePresent(
+ connectionLog.logEntries().get(0), SSLHandshakeException.class, SslHandshakeFailure.INCOMPATIBLE_PROTOCOLS.failureType());
}
@Test
@@ -697,9 +696,8 @@ public class HttpServerTest {
.add(MetricDefinitions.SSL_HANDSHAKE_FAILURE_INCOMPATIBLE_CIPHERS, 1L, MetricConsumerMock.STATIC_CONTEXT);
assertTrue(driver.close());
Assertions.assertThat(connectionLog.logEntries()).hasSize(1);
- ConnectionLogEntry logEntry = connectionLog.logEntries().get(0);
- Assertions.assertThat(logEntry.sslHandshakeFailureException()).hasValue(SSLHandshakeException.class.getName());
- Assertions.assertThat(logEntry.sslHandshakeFailureType()).hasValue(SslHandshakeFailure.INCOMPATIBLE_CIPHERS.failureType());
+ assertSslHandshakeFailurePresent(
+ connectionLog.logEntries().get(0), SSLHandshakeException.class, SslHandshakeFailure.INCOMPATIBLE_CIPHERS.failureType());
}
@Test
@@ -727,8 +725,8 @@ public class HttpServerTest {
assertTrue(driver.close());
Assertions.assertThat(connectionLog.logEntries()).hasSize(1);
ConnectionLogEntry logEntry = connectionLog.logEntries().get(0);
- Assertions.assertThat(logEntry.sslHandshakeFailureException()).hasValue(SSLHandshakeException.class.getName());
- Assertions.assertThat(logEntry.sslHandshakeFailureType()).hasValue(SslHandshakeFailure.INVALID_CLIENT_CERT.failureType());
+ assertSslHandshakeFailurePresent(
+ connectionLog.logEntries().get(0), SSLHandshakeException.class, SslHandshakeFailure.INVALID_CLIENT_CERT.failureType());
}
@Test
@@ -912,6 +910,15 @@ public class HttpServerTest {
}
}
+ private static void assertSslHandshakeFailurePresent(
+ ConnectionLogEntry entry, Class<? extends SSLHandshakeException> expectedException, String expectedType) {
+ Assertions.assertThat(entry.sslHandshakeFailure()).isPresent();
+ ConnectionLogEntry.SslHandshakeFailure failure = entry.sslHandshakeFailure().get();
+ assertEquals(expectedType, failure.type());
+ ExceptionEntry exceptionEntry = failure.exceptionChain().get(0);
+ assertEquals(expectedException.getName(), exceptionEntry.name());
+ }
+
private static TestDriver createSslWithProxyProtocolTestDriver(
Path certificateFile, Path privateKeyFile, RequestLog requestLog,
ConnectionLog connectionLog, boolean mixedMode) {