diff --git a/documentation/jetty-documentation/src/main/asciidoc/programming-guide/arch-listener.adoc b/documentation/jetty-documentation/src/main/asciidoc/programming-guide/arch-listener.adoc index ff54554bf145..4d3a328c4cbd 100644 --- a/documentation/jetty-documentation/src/main/asciidoc/programming-guide/arch-listener.adoc +++ b/documentation/jetty-documentation/src/main/asciidoc/programming-guide/arch-listener.adoc @@ -23,6 +23,13 @@ Applications can register listeners to these components to be notified of the ev This section lists the listeners available in the Jetty components, but the events and listener APIs are discussed in the component specific sections. +Listeners common to both client and server: + * xref:pg-arch-bean-listener[] * xref:pg-arch-io-connection-listener[] +* xref:pg-client-http-configuration-tls-listener[] +* xref:pg-server-http-connector-protocol[] + +Listeners that are server specific: + * xref:pg-server-http-request-processing-events[] diff --git a/documentation/jetty-documentation/src/main/asciidoc/programming-guide/client/http/client-http-configuration.adoc b/documentation/jetty-documentation/src/main/asciidoc/programming-guide/client/http/client-http-configuration.adoc index 62e47d66c1ad..9fbce705fa00 100644 --- a/documentation/jetty-documentation/src/main/asciidoc/programming-guide/client/http/client-http-configuration.adoc +++ b/documentation/jetty-documentation/src/main/asciidoc/programming-guide/client/http/client-http-configuration.adoc @@ -57,17 +57,32 @@ You can configure the `SslContextFactory.Client` to skip the validation of the s include::../../{doc_code}/org/eclipse/jetty/docs/programming/client/http/HTTPClientDocs.java[tags=tlsNoValidation] ---- -When you disable the validation of the server host name at the TLS level, you are strongly recommended to enable it at the application level, otherwise you may risk to connect to a server different from the one you intend to connect to: +When you disable the validation of the server host name at the TLS level, you are strongly recommended to enable it at the application level. +Failing to do so puts you at risk of connecting to a server different from the one you intend to connect to: [source,java,indent=0] ---- include::../../{doc_code}/org/eclipse/jetty/docs/programming/client/http/HTTPClientDocs.java[tags=tlsAppValidation] ---- -You may have the validation of the server host name enabled at both the TLS level and application level, typically when you want to further restrict the client to connect only to a smaller set of server hosts than those allowed in the certificate sent by the server. +Enabling server host name validation at both the TLS level and application level allow you to further restrict the set of server hosts the client can connect to, among those allowed in the certificate sent by the server. + +Entirely disabling server host name validation is not recommended, but may be done in controlled environments. + +Even with server host name validation disabled, the validation of the certificate chain, by validating cryptographic signatures and validity dates is still performed. Please refer to the `SslContextFactory.Client` link:{javadoc-url}/org/eclipse/jetty/util/ssl/SslContextFactory.Client.html[javadocs] for the complete list of configurable parameters. +[[pg-client-http-configuration-tls-listener]] +====== HttpClient `SslHandshakeListener` + +Applications may register a `org.eclipse.jetty.io.ssl.SslHandshakeListener` to be notified of TLS handshakes success or failure, by adding the `SslHandshakeListener` as a bean to `HttpClient`: + +[source,java,indent=0,options=nowrap] +---- +include::../../{doc_code}/org/eclipse/jetty/docs/programming/client/http/HTTPClientDocs.java[tags=sslHandshakeListener] +---- + [[pg-client-http-configuration-tls-truststore]] ====== HttpClient TLS TrustStore Configuration TODO diff --git a/documentation/jetty-documentation/src/main/asciidoc/programming-guide/server/http/server-http-connector.adoc b/documentation/jetty-documentation/src/main/asciidoc/programming-guide/server/http/server-http-connector.adoc index 1b1c0d59092b..71c9abd11b04 100644 --- a/documentation/jetty-documentation/src/main/asciidoc/programming-guide/server/http/server-http-connector.adoc +++ b/documentation/jetty-documentation/src/main/asciidoc/programming-guide/server/http/server-http-connector.adoc @@ -109,11 +109,24 @@ include::../../{doc_code}/org/eclipse/jetty/docs/programming/server/http/HTTPSer [[pg-server-http-connector-protocol]] ===== Configuring Protocols -For each accepted socket connection, the server `Connector` asks a `ConnectionFactory` to create a `Connection` object that handles the traffic on that socket connection, parsing and generating bytes for a specific protocol (see xref:pg-arch-io[this section] for more details about `Connection` objects). - -A server `Connector` can be configured with one or more ``ConnectionFactory``s. +A server `Connector` can be configured with one or more ``ConnectionFactory``s, and this list of ``ConnectionFactory``s represents the protocols that the `Connector` can understand. If no `ConnectionFactory` is specified then `HttpConnectionFactory` is implicitly configured. +For each accepted connection, the server `Connector` asks a `ConnectionFactory` to create a `Connection` object that handles the traffic on that connection, parsing and generating bytes for a specific protocol (see xref:pg-arch-io[this section] for more details about `Connection` objects). + +TIP: You can listen for `Connection` open and close events as detailed in xref:pg-arch-io-connection-listener[this section]. + +Secure protocols like secure HTTP/1.1, secure HTTP/2 or HTTP/3 (HTTP/3 is intrinsically secure -- there is no clear-text HTTP/3) require an `SslContextFactory.Server` to be configured with a KeyStore. + +For HTTP/1.1 and HTTP/2, `SslContextFactory.Server` is used in conjunction with `SSLEngine`, which drives the TLS handshake that establishes the secure communication. + +Applications may register a `org.eclipse.jetty.io.ssl.SslHandshakeListener` to be notified of TLS handshakes success or failure, by adding the `SslHandshakeListener` as a bean to the `Connector`: + +[source,java,indent=0] +---- +include::../../{doc_code}/org/eclipse/jetty/docs/programming/server/http/HTTPServerDocs.java[tags=sslHandshakeListener] +---- + [[pg-server-http-connector-protocol-http11]] ====== Clear-Text HTTP/1.1 diff --git a/documentation/jetty-documentation/src/main/java/org/eclipse/jetty/docs/programming/client/http/HTTPClientDocs.java b/documentation/jetty-documentation/src/main/java/org/eclipse/jetty/docs/programming/client/http/HTTPClientDocs.java index 1c73a3a25405..9aa2b2040f2f 100644 --- a/documentation/jetty-documentation/src/main/java/org/eclipse/jetty/docs/programming/client/http/HTTPClientDocs.java +++ b/documentation/jetty-documentation/src/main/java/org/eclipse/jetty/docs/programming/client/http/HTTPClientDocs.java @@ -24,6 +24,8 @@ import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLException; import org.eclipse.jetty.client.AsyncRequestContent; import org.eclipse.jetty.client.Authentication; @@ -69,6 +71,7 @@ import org.eclipse.jetty.io.ClientConnectionFactory; import org.eclipse.jetty.io.ClientConnector; import org.eclipse.jetty.io.Content; +import org.eclipse.jetty.io.ssl.SslHandshakeListener; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.component.LifeCycle; import org.eclipse.jetty.util.ssl.SslContextFactory; @@ -145,6 +148,35 @@ public void tlsAppValidation() // end::tlsAppValidation[] } + public void sslHandshakeListener() + { + // tag::sslHandshakeListener[] + // Create a SslHandshakeListener. + SslHandshakeListener listener = new SslHandshakeListener() + { + @Override + public void handshakeSucceeded(Event event) throws SSLException + { + SSLEngine sslEngine = event.getSSLEngine(); + System.getLogger("tls").log(INFO, "TLS handshake successful to %s", sslEngine.getPeerHost()); + } + + @Override + public void handshakeFailed(Event event, Throwable failure) + { + SSLEngine sslEngine = event.getSSLEngine(); + System.getLogger("tls").log(ERROR, "TLS handshake failure to %s", sslEngine.getPeerHost(), failure); + } + }; + + HttpClient httpClient = new HttpClient(); + + // Add the SslHandshakeListener as bean to HttpClient. + // The listener will be notified of TLS handshakes success and failure. + httpClient.addBean(listener); + // end::sslHandshakeListener[] + } + public void simpleBlockingGet() throws Exception { // tag::simpleBlockingGet[] diff --git a/documentation/jetty-documentation/src/main/java/org/eclipse/jetty/docs/programming/server/http/HTTPServerDocs.java b/documentation/jetty-documentation/src/main/java/org/eclipse/jetty/docs/programming/server/http/HTTPServerDocs.java index a2eed0eb2850..48c0c3930657 100644 --- a/documentation/jetty-documentation/src/main/java/org/eclipse/jetty/docs/programming/server/http/HTTPServerDocs.java +++ b/documentation/jetty-documentation/src/main/java/org/eclipse/jetty/docs/programming/server/http/HTTPServerDocs.java @@ -22,6 +22,8 @@ import java.util.Set; import java.util.TimeZone; import java.util.concurrent.CompletableFuture; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLException; import jakarta.servlet.ServletInputStream; import jakarta.servlet.http.HttpServlet; @@ -48,6 +50,7 @@ import org.eclipse.jetty.http3.server.HTTP3ServerConnectionFactory; import org.eclipse.jetty.http3.server.HTTP3ServerConnector; import org.eclipse.jetty.io.Content; +import org.eclipse.jetty.io.ssl.SslHandshakeListener; import org.eclipse.jetty.rewrite.handler.CompactPathRule; import org.eclipse.jetty.rewrite.handler.RedirectRegexRule; import org.eclipse.jetty.rewrite.handler.RewriteHandler; @@ -90,6 +93,7 @@ import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.thread.QueuedThreadPool; +import static java.lang.System.Logger.Level.ERROR; import static java.lang.System.Logger.Level.INFO; import static java.nio.charset.StandardCharsets.UTF_8; @@ -317,6 +321,37 @@ public void lifeCycleStarted(LifeCycle lifeCycle) // end::sameRandomPort[] } + public void sslHandshakeListener() throws Exception + { + // tag::sslHandshakeListener[] + // Create a SslHandshakeListener. + SslHandshakeListener listener = new SslHandshakeListener() + { + @Override + public void handshakeSucceeded(Event event) throws SSLException + { + SSLEngine sslEngine = event.getSSLEngine(); + System.getLogger("tls").log(INFO, "TLS handshake successful to %s", sslEngine.getPeerHost()); + } + + @Override + public void handshakeFailed(Event event, Throwable failure) + { + SSLEngine sslEngine = event.getSSLEngine(); + System.getLogger("tls").log(ERROR, "TLS handshake failure to %s", sslEngine.getPeerHost(), failure); + } + }; + + Server server = new Server(); + ServerConnector connector = new ServerConnector(server); + server.addConnector(connector); + + // Add the SslHandshakeListener as bean to ServerConnector. + // The listener will be notified of TLS handshakes success and failure. + connector.addBean(listener); + // end::sslHandshakeListener[] + } + public void http11() throws Exception { // tag::http11[]