Merged branch 'jetty-10.0.x' into 'jetty-11.0.x'.

This commit is contained in:
Simone Bordet 2020-10-30 16:55:11 +01:00
commit 0741f1bb65
25 changed files with 669 additions and 515 deletions

View File

@ -30,6 +30,5 @@ Typical uses of the JMX technology include:
The JMX API includes remote access, so a remote management program can interact with a running application for these purposes.
include::using-jmx.adoc[]
include::jetty-jmx-annotations.adoc[]
include::jetty-jconsole.adoc[]

View File

@ -1,360 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under
// the terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0
//
// This Source Code may also be made available under the following
// Secondary Licenses when the conditions for such availability set
// forth in the Eclipse Public License, v. 2.0 are satisfied:
// the Apache License v2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
[[using-jmx]]
=== Using JMX with Jetty
Jetty's architecture is based on POJO components (see xref:basic-architecture[]).
These components are organized in a tree and each component may have a lifecycle that spans the `Server` lifetime, or a web application lifetime, or even shorter lifetimes such as that of a TCP connection.
Every time a component is added or removed from the component tree, an event is emitted, and link:{JDURL}/org/eclipse/jetty/util/component/Container.html[`Container.Listener`] implementations can listen to those events and perform additional actions.
One such `Container.Listener` is `MBeanContainer` that uses `ObjectMBean` to create an MBean from an arbitrary POJO, and register/unregister the MBean to/from the platform `MBeanServer`.
Jetty components are annotated with xref:jetty-jmx-annotations[] and provide specific JMX details so that `ObjectMBean` can build a more precise representation of the JMX metadata associated with the component POJO.
Therefore, when a component is added to the component tree, `MBeanContainer` is notified, it creates the MBean from the component POJO and registers it to the `MBeanServer`.
Similarly, when a component is removed from the tree, `MBeanContainer` is notified, and unregisters the MBean from the `MBeanServer`.
The Jetty MBeans can be accessed via any JMX console such as Java Mission Control (JMC), VisualVM, JConsole or others.
[[configuring-jmx]]
==== Configuring JMX
This guide describes the various ways to initialize and configure the Jetty JMX integration.
Configuring the Jetty JMX integration only registers the Jetty MBeans into the platform `MBeanServer`, and therefore the MBeans can only be accessed locally (from the same machine), not from remote machines.
This means that this configuration is enough for development, where you have easy access (with graphical user interface) to the machine where Jetty runs, but it is typically not enough when the machine Jetty where runs is remote, or only accessible via SSH or otherwise without graphical user interface support.
In these cases, you have to enable link:#jmx-remote-access[JMX Remote Access].
[[jmx-standalone-jetty]]
===== Standalone Jetty Server
JMX is not enabled by default in the Jetty distribution.
To enable JMX in the Jetty distribution run the following, where `{$jetty.home}` is the directory where you have the Jetty distribution installed, and `${jetty.base}` is the directory where you have your Jetty configuration (see link:#startup-base-and-home[the documentation for Jetty base vs. home examples]):
[source, screen, subs="{sub-order}"]
----
$ cd ${jetty.base}
$ java -jar {$jetty.home}/start.jar --add-to-start=jmx
----
Running the above command will append the available configurable elements of the `jmx` module to the `{$jetty.base}/start.ini` file, or create the `${jetty.base}/start.d/jmx.ini` file.
[[jmx-embedded-jetty]]
===== Embedded Jetty Server
When running Jetty embedded into an application, create and configure an `MBeanContainer` instance as follows:
[source, java]
----
Server server = new Server();
// Setup JMX.
MBeanContainer mbeanContainer = new MBeanContainer(ManagementFactory.getPlatformMBeanServer());
server.addBean(mbeanContainer);
// Export the loggers as MBeans.
server.addBean(Log.getLog());
----
Because logging is initialized prior to the `MBeanContainer` (even before the `Server` itself), it is necessary to register the logger manually via `server.addBean()` so that the loggers may show up in the JMX tree as MBeans.
[[jmx-jetty-maven-plugin]]
===== Using the Jetty Maven Plugin with JMX
If you are using the link:#jetty-maven-plugin[Jetty Maven plugin] you should copy the `${jetty.home}/etc/jetty-jmx.xml` file into your webapp project somewhere, such as `src/main/config/etc/`, then add a `<jettyXml>` element to the `<configuration>` element of the Jetty Maven Plugin:
[source, xml, subs="{sub-order}"]
----
<plugin>
<groupid>org.eclipse.jetty</groupid>
<artifactid>jetty-maven-plugin</artifactid>
<version>{VERSION}</version>
<configuration>
<scanintervalseconds>10</scanintervalseconds>
<jettyXml>src/main/config/etc/jetty-jmx.xml</jettyXml>
</configuration>
</plugin>
----
[[accessing-jetty-mbeans]]
==== Using JConsole or Java Mission Control to Access Jetty MBeans
The simplest way to access the MBeans that Jetty publishes is to use link:#jetty-jconsole[Java Mission Control (JMC) or JConsole.]
Both these tools can connect to local or remote JVMs to display the MBeans.
For local access, you just need to start JConsole or JMC and then choose from their user interface the local JVM you want to connect to.
For remote access, you need first to enable JMX Remote Access in Jetty.
[[jmx-remote-access]]
==== Enabling JMX Remote Access
There are two ways of enabling remote connectivity so that JConsole or JMC can connect to the remote JVM to visualize MBeans.
* Use the `com.sun.management.jmxremote` system property on the command line.
Unfortunately, this solution does not work well with firewalls and is not flexible.
* Use Jetty's `jmx-remote` module or - equivalently - the `ConnectorServer` class.
`ConnectorServer` will use by default RMI to allow connection from remote clients,
and it is a wrapper around the standard JDK class `JMXConnectorServer`, which is the class that provides remote access to JMX clients.
Connecting to the remote JVM is a two step process:
* First, the client will connect to the RMI _registry_ to download the RMI stub for the `JMXConnectorServer`; this RMI stub contains the IP address and port to connect to the RMI server, i.e. the remote `JMXConnectorServer`.
* Second, the client uses the RMI stub to connect to the RMI _server_ (i.e. the remote `JMXConnectorServer`) typically on an address and port that may be different from the RMI registry address and port.
The configuration for the RMI registry and the RMI server is specified by a `JMXServiceURL`.
The string format of an RMI `JMXServiceURL` is:
[source, screen, subs="{sub-order}"]
----
service:jmx:rmi://<rmi_server_host>:<rmi_server_port>/jndi/rmi://<rmi_registry_host>:<rmi_registry_port>/jmxrmi
----
Default values are:
[source, screen, subs="{sub-order}"]
----
rmi_server_host = localhost
rmi_server_port = 1099
rmi_registry_host = localhost
rmi_registry_port = 1099
----
With the default configuration, only clients that are local to the server machine can connect to the RMI registry and RMI server - this is done for security reasons.
With this configuration it would still be possible to access the MBeans from remote using a link:#jmx-remote-access-ssh-tunnel[SSH tunnel.]
By specifying an appropriate `JMXServiceURL`, you can fine tune the network interfaces the RMI registry and the RMI server bind to, and the ports that the RMI registry and the RMI server listen to.
The RMI server and RMI registry hosts and ports can be the same (as in the default configuration) because RMI is able to multiplex traffic arriving to a port to multiple RMI objects.
If you need to allow JMX remote access through a firewall, you must open both the RMI registry and the RMI server ports.
Examples:
[source, screen, subs="{sub-order}"]
----
service:jmx:rmi:///jndi/rmi:///jmxrmi
rmi_server_host = local host address
rmi_server_port = randomly chosen
rmi_registry_host = local host address
rmi_registry_port = 1099
service:jmx:rmi://0.0.0.0:1099/jndi/rmi://0.0.0.0:1099/jmxrmi
rmi_server_host = any address
rmi_server_port = 1099
rmi_registry_host = any address
rmi_registry_port = 1099
service:jmx:rmi://localhost:1100/jndi/rmi://localhost:1099/jmxrmi
rmi_server_host = loopback address
rmi_server_port = 1100
rmi_registry_host = loopback address
rmi_registry_port = 1099
----
[NOTE]
====
When `ConnectorServer` is started, its RMI stub is exported to the RMI registry.
The RMI stub contains the IP address and port to connect to the RMI object, but the IP address is typically the machine host name, not the host specified in the `JMXServiceURL`.
To control the IP address stored in the RMI stub you need to set the system property `java.rmi.server.hostname` with the desired value.
This is especially important when binding the RMI server host to the loopback address for security reasons. See also link:#jmx-remote-access-ssh-tunnel[JMX Remote Access via SSH Tunnel.]
====
===== Enabling JMX Remote Access in Standalone Jetty Server
Similarly to link:#jmx-standalone-jetty[enabling JMX in a standalone Jetty server], you enable the `jmx-remote` module:
[source, screen, subs="{sub-order}"]
----
$ cd ${jetty.base}
$ java -jar {$jetty.home}/start.jar --add-to-start=jmx-remote
----
===== Enabling JMX Remote Access in Embedded Jetty
When running Jetty embedded into an application, create and configure a `ConnectorServer`:
[source, java, subs="{sub-order}"]
----
Server server = new Server();
// Setup JMX
MBeanContainer mbeanContainer = new MBeanContainer(ManagementFactory.getPlatformMBeanServer());
server.addBean(mbeanContainer);
// Setup ConnectorServer
JMXServiceURL jmxURL = new JMXServiceURL("rmi", null, 1999, "/jndi/rmi:///jmxrmi");
ConnectorServer jmxServer = new ConnectorServer(jmxURL, "org.eclipse.jetty.jmx:name=rmiconnectorserver");
server.addBean(jmxServer);
----
The `JMXServiceURL` above specifies that the RMI server binds to the wildcard address on port 1999, while the RMI registry binds to the wildcard address on port 1099 (the default RMI registry port).
[[jmx-remote-access-authorization]]
===== JMX Remote Access Authorization
The standard `JMXConnectorServer` provides several options to authorize access.
For a complete guide to controlling authentication and authorization in JMX, see https://blogs.oracle.com/lmalventosa/entry/jmx_authentication_authorization[Authentication and Authorization in JMX RMI connectors].
To authorize access to the `JMXConnectorServer` you can use this configuration, where the `jmx.password` and `jmx.access` files have the format specified in the blog entry above:
[source, xml, subs="{sub-order}"]
----
<New id="ConnectorServer" class="org.eclipse.jetty.jmx.ConnectorServer">
<Arg>
<New class="javax.management.remote.JMXServiceURL">
<Arg type="java.lang.String">rmi</Arg>
<Arg type="java.lang.String" />
<Arg type="java.lang.Integer">1099</Arg>
<Arg type="java.lang.String">/jndi/rmi:///jmxrmi</Arg>
</New>
</Arg>
<Arg>
<Map>
<Entry>
<Item>jmx.remote.x.access.file</Item>
<Item>
<New class="java.lang.String"><Arg><Property name="jetty.base" default="." />/resources/jmx.access</Arg></New>
</Item>
</Entry>
<Entry>
<Item>jmx.remote.x.password.file</Item>
<Item>
<New class="java.lang.String"><Arg><Property name="jetty.base" default="." />/resources/jmx.password</Arg></New>
</Item>
</Entry>
</Map>
</Arg>
<Arg>org.eclipse.jetty.jmx:name=rmiconnectorserver</Arg>
<Call name="start" />
</New>
----
Similarly, in code:
[source, java, subs="{sub-order}"]
----
JMXServiceURL jmxURL = new JMXServiceURL("rmi", null, 1099, "/jndi/rmi:///jmxrmi");
Map<String, Object> env = new HashMap<>();
env.put("jmx.remote.x.access.file", "resources/jmx.access");
env.put("jmx.remote.x.password.file", "resources/jmx.password");
ConnectorServer jmxServer = new ConnectorServer(jmxURL, env, "org.eclipse.jetty.jmx:name=rmiconnectorserver");
jmxServer.start();
----
Calling `ConnectorServer.start()` may be explicit as in the examples above, or can be skipped when adding the `ConnectorServer` as a bean to the `Server`, so that starting the `Server` will also start the `ConnectorServer`.
===== Securing JMX Remote Access with TLS
The JMX communication via RMI happens by default in clear-text.
It is possible to configure the `ConnectorServer` with a `SslContextFactory` so that the JMX communication via RMI is encrypted:
[source, xml, subs="{sub-order}"]
----
<New id="ConnectorServer" class="org.eclipse.jetty.jmx.ConnectorServer">
<Arg>
<New class="javax.management.remote.JMXServiceURL">
<Arg type="java.lang.String">rmi</Arg>
<Arg type="java.lang.String" />
<Arg type="java.lang.Integer">1099</Arg>
<Arg type="java.lang.String">/jndi/rmi:///jmxrmi</Arg>
</New>
</Arg>
<Arg />
<Arg>org.eclipse.jetty.jmx:name=rmiconnectorserver</Arg>
<Arg><Ref refid="sslContextFactory" /></Arg>
</New>
----
Similarly, in code:
[source, java, subs="{sub-order}"]
----
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
sslContextFactory.setKeyStorePath("/path/to/keystore");
sslContextFactory.setKeyStorePassword("secret");
JMXServiceURL jmxURL = new JMXServiceURL("rmi", null, 1099, "/jndi/rmi:///jmxrmi");
ConnectorServer jmxServer = new ConnectorServer(jmxURL, null, "org.eclipse.jetty.jmx:name=rmiconnectorserver", sslContextFactory);
----
It is possible to use the same `SslContextFactory` used to configure the Jetty `ServerConnector` that supports TLS for the HTTP protocol.
This is used in the XML example above: the `SslContextFactory` configured for the TLS `ServerConnector` is registered with an id of `sslContextFactory` which is referenced in the XML via the `Ref` element.
The keystore must contain a valid certificate signed by a Certification Authority.
The RMI mechanic is the usual one: the RMI client (typically a monitoring console) will connect first to the RMI registry (using TLS), download the RMI server stub that contains the address and port of the RMI server to connect to, then connect to the RMI server (using TLS).
This also mean that if the RMI registry and the RMI server are on different hosts, the RMI client must have available the cryptographic material to validate both hosts.
Having certificates signed by a Certification Authority simplifies by a lot the configuration needed to get the JMX communication over TLS working properly.
If that is not the case (for example the certificate is self-signed), then you need to specify the required system properties that allow RMI (especially when acting as an RMI client) to retrieve the cryptographic material necessary to establish the TLS connection.
For example, trying to connect using the JDK standard `JMXConnector` with both the RMI server and the RMI registry to `domain.com`:
[source, java, subs="{sub-order}"]
----
// System properties necessary for an RMI client to trust a self-signed certificate.
System.setProperty("javax.net.ssl.trustStore", "/path/to/trustStore");
System.setProperty("javax.net.ssl.trustStorePassword", "secret");
JMXServiceURL jmxURL = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://domain.com:1100/jmxrmi")
Map<String, Object> clientEnv = new HashMap<>();
// Required to connect to the RMI registry via TLS.
clientEnv.put(ConnectorServer.RMI_REGISTRY_CLIENT_SOCKET_FACTORY_ATTRIBUTE, new SslRMIClientSocketFactory());
try (JMXConnector client = JMXConnectorFactory.connect(jmxURL, clientEnv))
{
Set<ObjectName> names = client.getMBeanServerConnection().queryNames(null, null);
}
----
Similarly, to launch JMC:
[source, java, subs="{sub-order}"]
----
$ jmc -vmargs -Djavax.net.ssl.trustStore=/path/to/trustStore -Djavax.net.ssl.trustStorePassword=secret
----
Note that these system properties are required when launching the `ConnectorServer` too, on the server, because it acts as an RMI client with respect to the RMI registry.
[[jmx-remote-access-ssh-tunnel]]
===== JMX Remote Access with Port Forwarding via SSH Tunnel
You can access JMX MBeans on a remote machine when the RMI ports are not open, for example because of firewall policies, but you have SSH access to the machine using local port forwarding via a SSH tunnel.
In this case you want to configure the `ConnectorServer` with a `JMXServiceURL` that binds the RMI server and the RMI registry to the loopback interface only: `service:jmx:rmi://localhost:1099/jndi/rmi://localhost:1099/jmxrmi`.
Then you setup the local port forwarding with the SSH tunnel:
[source, screen, subs="{sub-order}"]
----
$ ssh -L 1099:localhost:1099 <user>@<machine_host>
----
Now you can use JConsole or JMC to connect to `localhost:1099` on your local computer.
The traffic will be forwarded to `machine_host` and when there, SSH will forward the traffic to `localhost:1099`, which is exactly where the `ConnectorServer` listens.
When you configure `ConnectorServer` in this way, you must set the system property `-Djava.rmi.server.hostname=localhost`, on the server.
This is required because when the RMI server is exported, its address and port are stored in the RMI stub. You want the address in the RMI stub to be `localhost` so that when the RMI stub is downloaded to the remote client, the RMI communication will go through the SSH tunnel.

View File

@ -38,3 +38,5 @@ include::annotations/chapter.adoc[]
include::jsp/chapter.adoc[]
include::jndi/chapter.adoc[]
include::jaas/chapter.adoc[]
include::jmx/chapter.adoc[]
include::troubleshooting/chapter.adoc[]

View File

@ -36,6 +36,7 @@ If you know Eclipse Jetty already, jump to a feature:
* xref:og-jaas[JAAS]
* xref:og-jndi[JNDI]
* xref:og-jsp[JSP]
* xref:og-jmx[Monitoring & Management]
TODO
@ -50,8 +51,4 @@ TODO
* xref:og-protocols-http2c[Configure Clear-Text HTTP/2]
* xref:og-protocols-http2s[Configure Secure HTTP/2]
* xref:og-protocols-proxy[Configure Jetty Behind a Load Balancer or Reverse Proxy]
TODO
* Jetty Behind a Load Balancer
** Forward Header Customizer
* xref:og-troubleshooting[Troubleshooting]

View File

@ -0,0 +1,31 @@
//
// ========================================================================
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under
// the terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0
//
// This Source Code may also be made available under the following
// Secondary Licenses when the conditions for such availability set
// forth in the Eclipse Public License, v. 2.0 are satisfied:
// the Apache License v2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
[[og-jmx]]
=== Eclipse Jetty Monitoring & Management
Monitoring and management of a Jetty server is important because it allows you to monitor the status of the server (_"Is the server processing requests?"_) and to manage -- i.e. read and possibly change -- its configuration.
The ability to read and change the Jetty configuration is very important for troubleshooting Jetty -- please refer to the xref:og-troubleshooting[troubleshooting section] for more information.
Jetty relies on the Java Management Extensions (JMX) APIs included in OpenJDK to provide monitoring and management.
The JMX APIs support a JVM-local `MBeanServer`, accessible only from within the JVM itself (or by tools that can _attach_ to a running JVM), and a way to expose the `MBeanServer` to remote clients via Java's RMI (Remote Method Invocation).
include::jmx-local.adoc[]
include::jmx-remote.adoc[]

View File

@ -0,0 +1,39 @@
//
// ========================================================================
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under
// the terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0
//
// This Source Code may also be made available under the following
// Secondary Licenses when the conditions for such availability set
// forth in the Eclipse Public License, v. 2.0 are satisfied:
// the Apache License v2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
[[og-jmx-local]]
==== Enabling Local JMX Support
As with many other Jetty features, local JMX support is enabled with the `jmx` Jetty module:
----
$ java -jar $JETTY_HOME/start.jar --add-module=jmx
----
With the `jmx` Jetty module enabled, Jetty components will be exported as JMX _MBeans_ to the JVM platform `MBeanServer`, so that they can be accessed by JMX compliant tools.
Each Jetty component will export to its correspondent MBean relevant configuration parameters, so that a JMX tool can read and possibly change the component configuration through the MBean.
Note that the Jetty MBeans are registered into the platform `MBeanServer`, but are not available to remote clients: they are _local_ to the JVM.
This configuration is useful when you develop and test your Jetty server locally.
JMX compliant tools such as link:https://adoptopenjdk.net/jmc.html[Java Mission Control (JMC)] can be started locally on your machine and can attach to other JVMs running on your machine, showing you the registered MBeans among which you will find the Jetty MBeans.
NOTE: Enabling only the local JMX support is the most secure option for monitoring and management, but only users that have local access to the JVM will be able to browse the MBeans.
If you need to access the MBeans from a remote machine, read xref:og-jmx-remote[this section].

View File

@ -0,0 +1,254 @@
//
// ========================================================================
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under
// the terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0
//
// This Source Code may also be made available under the following
// Secondary Licenses when the conditions for such availability set
// forth in the Eclipse Public License, v. 2.0 are satisfied:
// the Apache License v2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
[[og-jmx-remote]]
==== Enabling Remote JMX Support
There are two ways to configure a Jetty server so that it is possible to access the JVM platform MBeans from remote clients:
* Use the `com.sun.management.jmxremote` and related system properties when starting Jetty.
Unfortunately, this solution does not work well with firewalls, and will not be discussed further.
* Use the `jmx-remote` Jetty module.
Both ways use Java's Remote Method Invocation (RMI) to communicate between the client and the server.
[IMPORTANT]
.Refresher: How RMI Works
====
A server application that wants to make an object available to remote clients must _export_ the object.
Exporting an object creates an RMI _stub_ that contains the host/port of the RMI _server_ that accepts incoming invocations from clients and forwards them to the object.
During the creation of the RMI stub, the host stored in the RMI stub is retrieved from the local name resolution system (for example, in Linux, from `/etc/hosts`).
The RMI stub is then sent, along with a name that uniquely identifies the object, to the RMI _registry_.
The RMI registry is a service that maps names to RMI stubs; it may be external to both clients and server, although often it is part of the server JVM.
When a client application wants to connect to the server object using RMI, it first connects to the RMI registry to download the RMI stub for the RMI server; recall that the RMI stub contains the host/port to connect to the RMI server.
Then, the client uses the RMI stub to connect to the RMI server, typically to a host/port that may be different from the RMI registry host/port (in particular, by default the RMI server port will be different from the RMI registry port).
====
Remote access to the platform MBeans, and therefore the Jetty MBeans, is enabled by the `jmx-remote` Jetty module:
----
$ java -jar $JETTY_HOME/start.jar --add-module=jmx-remote
----
This command creates the `jmx-remote.ini` file:
[source,subs=quotes]
----
JETTY_BASE
└── start.d
└── #jmx-remote.ini#
----
Enabling the `jmx-remote` module transitively enables the xref:og-jmx-local[`jmx` module] as well.
The configuration for the RMI registry and the RMI server is specified by a `JMXServiceURL`.
The string format of an RMI `JMXServiceURL` is the following:
----
service:jmx:rmi://<rmi_server_host>:<rmi_server_port>/jndi/rmi://<rmi_registry_host>:<rmi_registry_port>/jmxrmi
----
Below you can find examples of ``JMXServiceURL``s:
[source,subs=quotes]
----
*service:jmx:rmi:///jndi/rmi:///jmxrmi*
where:
rmi_server_host = local host address
rmi_server_port = randomly chosen
rmi_registry_host = local host address
rmi_registry_port = 1099
*service:jmx:rmi://0.0.0.0:1099/jndi/rmi://0.0.0.0:1099/jmxrmi*
where:
rmi_server_host = any address
rmi_server_port = 1099
rmi_registry_host = any address
rmi_registry_port = 1099
*service:jmx:rmi://localhost:1100/jndi/rmi://localhost:1099/jmxrmi*
where:
rmi_server_host = loopback address
rmi_server_port = 1100
rmi_registry_host = loopback address
rmi_registry_port = 1099
----
The default `JMXServiceURL` configured by the `jmx-remote` module is the following:
----
service:jmx:rmi://localhost:1099/jndi/rmi://localhost:1099/jmxrmi
----
With the default configuration, only clients that are local to the server machine can connect to the RMI registry and RMI server - this is done for security reasons.
However, even with this local-only configuration, it would still be possible to access the MBeans from remote using an SSH tunnel, as explained in xref:og-jmx-remote-ssh-tunnel[this section].
By specifying an appropriate `JMXServiceURL`, you can fine tune the network address the RMI registry and the RMI server bind to, and the ports that the RMI registry and the RMI server listen to.
The RMI server and RMI registry hosts and ports can be the same (as in the default configuration) because RMI is able to multiplex traffic arriving to one port to multiple RMI objects.
If you need to allow JMX remote access through a firewall, you must open both the RMI registry and the RMI server ports.
The default configuration simplifies the firewall configuration because you only need to open port `1099`.
[NOTE]
====
When Jetty is started with the `jmx-remote` module enabled, the RMI stub of the Jetty component that provides access to the MBeans is exported to the RMI registry.
The RMI stub contains the host/port to connect to the RMI server, but the host is typically the machine host name, not the host specified in the `JMXServiceURL` (the latter is only used to specify the network address the RMI server binds to).
To control the host stored in the RMI stub you need to set the system property `java.rmi.server.hostname` with the desired value in the module configuration file, `jmx-remote.ini`.
====
IMPORTANT: If your client cannot connect to the server, the most common cause is a mismatch between the RMI server host of the `JMXServiceURL` and the RMI server host of the RMI stub.
You can customize the RMI server host/port, the RMI registry host/port and the system property `java.rmi.server.hostname` by editing the `jmx-remote.ini` configuration file.
Further information about the `jmx-remote` module configuration can be found xref:og-module-jmx-remote[here].
[[og-jmx-remote-ssh-tunnel]]
===== Remote JMX Access with Port Forwarding via SSH Tunnel
You can access JMX MBeans on a remote machine when the RMI ports are not open, for example because of firewall policies, but you have SSH access to the machine, using local port forwarding via an SSH tunnel.
In this case you want to configure the `JMXServiceURL` that binds the RMI server and the RMI registry to the loopback interface only and to the same port:
----
service:jmx:rmi://localhost:1099/jndi/rmi://localhost:1099/jmxrmi
----
You must set the system property `-Djava.rmi.server.hostname=localhost` so that the RMI stub contains `localhost` as the host name to connect to.
This is, incidentally, the default configuration of the `jmx-remote` module.
Then you setup the local port forwarding with the SSH tunnel:
----
$ ssh -L 1099:localhost:1099 <user>@<machine_host>
----
Thanks to the local port forwarding of the SSH tunnel, when the client connects to `localhost:1099` on your local computer, the traffic will be forwarded to `machine_host` and when there, the SSH daemon will forward the traffic to `localhost:1099` on `machine_host`, which is exactly where the RMI server and the RMI registry listens to.
The client first contacts the RMI registry, so it connects to `localhost:1099` on your local computer; the traffic is forwarded to `machine_host` through the SSH tunnel, connects to the RMI registry and the RMI stub is downloaded to the client.
Then the client uses the RMI stub to connect to the RMI server. The RMI stub contains `localhost` as the RMI server host because that is what you have configured with the system property `java.rmi.server.hostname`.
The client will connect again to `localhost:1099` on your local computer, this time to contact the RMI server; the traffic is forwarded to `machine_host` through the SSH tunnel, arrives to `machine_host` and connects to the RMI server.
[[og-jmx-remote-auth]]
===== Remote JMX Access Authentication & Authorization
The standard `javax.management.remote.JMXConnectorServer` class, used by the `jmx-remote` module to provide remote JMX access to Jetty MBeans, provides several options to authenticate and authorize users.
For a complete guide to controlling authentication and authorization in JMX, see link:https://docs.oracle.com/en/java/javase/11/management/monitoring-and-management-using-jmx-technology.html[the official JMX documentation].
The simplest way to control JMX authentication and authorization is to specify two files: one contains username and password pairs, and the other contains username and permission pairs.
This is achieved by enbling the `jmx-remote-auth` Jetty module:
----
$ java -jar $JETTY_HOME/start.jar --add-module=jmx-remote-auth
----
Enabling the `jmx-remote-auth` Jetty module creates the following files:
----
$JETTY_BASE
├── etc
│ ├── jmxremote.access
│ ├── jmxremote.password
│ └── jmx-remote-auth.xml
└── start.d
├── jmx-remote-auth.ini
└── jmx-remote.ini
----
Then you edit the `$JETTY_BASE/etc/jmxremote.password` file, adding the username/password pairs that you need:
.$JETTY_BASE/etc/jmxremote.password
----
# The file format is: <username> <password>
alice wonderland
bob marley
----
You must also edit the `$JETTY_BASE/etc/jmxremote.access` file to give permissions to your users:
.$JETTY_BASE/etc/jmxremote.access
----
# The file format is: <username> <readonly|readwrite>
alice readwrite
bob readonly
----
The above files define user `alice` with password `wonderland` to have `readwrite` access, and user `bob` with password `marley` to have `readonly` access.
[[og-jmx-remote-secure]]
===== Securing Remote JMX Access with TLS
The JMX communication via RMI happens by default in clear-text, but it is possible to secure the JMX communication via RMI with TLS.
If you want to reuse the configuration that you are using for the xref:og-protocols-https[`https` module], you can just enable the `jmx-remote-ssl.xml` Jetty module:
----
$ java -jar $JETTY_HOME/start.jar --add-module=jmx-remote-ssl
----
[NOTE]
====
The `jmx-remote-ssl` Jetty module depends on the `ssl` Jetty module that in turn requires a KeyStore (read xref:og-protocols-ssl[this section] for more information).
====
The KeyStore must contain a valid certificate signed by a Certification Authority.
Having certificates signed by a Certification Authority simplifies by a lot the configuration needed to get the RMI communication over TLS working properly.
The RMI mechanic is the usual one: the RMI client (typically a monitoring console) will connect first to the RMI registry (using TLS), download the RMI stub that contains the address and port of the RMI server to connect to, then connect to the RMI server (using TLS).
This also mean that if the RMI registry and the RMI server are on different hosts, the RMI client must have available the cryptographic material to validate the certificates from both hosts.
This is where having certificates signed by a Certification Authority simplifies the configuration: if they are signed by a well known Certification Authority, the client does not need any extra configuration -- everything will be handled by the Java runtime.
If the certificates are not signed by a Certification Authority (for example the certificate is self-signed), then you need to specify the TLS system properties that allow RMI (especially when acting as an RMI client) to retrieve the cryptographic material necessary to establish the TLS connection.
[IMPORTANT]
====
When the RMI server exports the `JMXConnectorServer` it acts as an RMI _client_ towards the RMI registry, and as such you must specify the TLS system properties as detailed below.
====
You must edit the `$JETTY_BASE/start.d/jmx-remote-ssl.ini` file and add the TrustStore path and password:
.$JETTY_BASE/start.d/jmx-remote-ssl.ini
----
--module=jmx-remote-ssl
# System properties necessary for non-trusted certificates.
-Djavax.net.ssl.trustStore=/path/to/trustStore.p12
-Djavax.net.ssl.trustStorePassword=password
----
[IMPORTANT]
====
The TrustStore must contain the certificate you want to trust.
If you are using self-signed certificates, the KeyStore already contains the self-signed certificate and therefore the KeyStore can be used as a TrustStore, and the system properties above can refer to the KeyStore path and password.
====
JMX compliant tools that offer a graphical user interface also must be started specifying the TrustStore path and password.
For example, to launch link:https://adoptopenjdk.net/jmc.html[Java Mission Control (JMC)]:
----
$ jmc -vmargs -Djavax.net.ssl.trustStore=/path/to/trustStore.p12 -Djavax.net.ssl.trustStorePassword=password
----

View File

@ -0,0 +1,44 @@
//
// ========================================================================
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under
// the terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0
//
// This Source Code may also be made available under the following
// Secondary Licenses when the conditions for such availability set
// forth in the Eclipse Public License, v. 2.0 are satisfied:
// the Apache License v2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
[[og-module-jmx-remote]]
==== Module `jmx-remote`
The `jmx-remote` module provides remote access to JMX clients.
The module properties to configure remote JMX connector are:
----
include::{JETTY_HOME}/modules/jmx-remote.mod[tags=documentation]
----
The system property `java.rmi.server.hostname` is specified with the usual notation, prepending a `-D` in front of the system property name.
The system property `java.rmi.server.hostname` is uncommented because it is necessary in the default configuration -- most systems do not have the local name resolution configured properly for remote access.
As an example, in a Linux machine named `beryl`, the `/etc/hosts` file may contain these entries:
----
127.0.0.1 localhost
127.0.1.1 beryl
----
If the system property `java.rmi.server.hostname` is not specified, the RMI implementation uses the host name `beryl` to figure out the IP address to store in the RMI stub, in this case `127.0.1.1`.
However, we the RMI server is configured to bind to `localhost`, i.e. `127.0.0.1`.
If the system property `java.rmi.server.hostname` is not specified, the RMI client will try to connect to `127.0.1.1` (because that's what in the RMI stub) and fail because nothing is listening on that address.

View File

@ -0,0 +1,23 @@
//
// ========================================================================
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under
// the terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0
//
// This Source Code may also be made available under the following
// Secondary Licenses when the conditions for such availability set
// forth in the Eclipse Public License, v. 2.0 are satisfied:
// the Apache License v2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
[[og-troubleshooting]]
=== Eclipse Jetty Troubleshooting
// TODO: see old docs under troubleshooting/*
TODO

View File

@ -2,29 +2,9 @@
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<!-- =========================================================== -->
<!-- Set the java.rmi.server.hostname property in case you've -->
<!-- got a misconfigured /etc/hosts entry or the like. -->
<!-- =========================================================== -->
<!--
<Call class="java.lang.System" name="setProperty">
<Arg>java.rmi.server.hostname</Arg>
<Arg>127.0.0.1</Arg>
</Call>
-->
<!-- Adds a remote JMXConnectorServer. The parameters of the constructor
below specify the JMXServiceURL, and the ObjectName string for the
JMXConnectorServer. The parameters of the JMXServiceURL constructor
specify the protocol that clients will use to connect to the remote JMX
connector (rmi), the hostname and port number of the RMI server, and the
URL path. Note that URL path contains the RMI registry hostname and port
number. Modify the port numbers if you need to comply with the firewall
requirements.
-->
<Call name="addBean">
<Arg>
<New id="ConnectorServer" class="org.eclipse.jetty.jmx.ConnectorServer">
<New id="JMXConnectorServer" class="org.eclipse.jetty.jmx.ConnectorServer">
<Arg>
<New class="javax.management.remote.JMXServiceURL">
<Arg type="java.lang.String">rmi</Arg>
@ -33,7 +13,7 @@
<Arg type="java.lang.String">/jndi/rmi://<Property name="jetty.jmxremote.rmiregistryhost" default="localhost"/>:<Property name="jetty.jmxremote.rmiregistryport" default="1099"/>/jmxrmi</Arg>
</New>
</Arg>
<Arg>org.eclipse.jetty.jmx:name=rmiconnectorserver</Arg>
<Arg>org.eclipse.jetty.jmx:name=jmxconnectorserver</Arg>
</New>
</Arg>
</Call>

View File

@ -0,0 +1,15 @@
[description]
Enables authentication and authorization for remote clients
that want to connect to JMX to access the platform MBeans,
via configuration files for user passwords and user roles.
[depend]
jmx-remote
[files]
basehome:modules/jmx.d/jmxremote.password|etc/jmxremote.password
basehome:modules/jmx.d/jmxremote.access|etc/jmxremote.access
basehome:modules/jmx.d/jmx-remote-auth.xml|etc/jmx-remote-auth.xml
[xml]
etc/jmx-remote-auth.xml

View File

@ -0,0 +1,12 @@
[description]
Enables secure remote RMI access to platform MBeans.
[depend]
ssl
jmx-remote
[files]
basehome:modules/jmx.d/jmx-remote-ssl.xml|etc/jmx-remote-ssl.xml
[xml]
etc/jmx-remote-ssl.xml

View File

@ -1,7 +1,5 @@
# DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[description]
Enables remote RMI access to JMX.
Enables clear-text remote RMI access to platform MBeans.
[depend]
jmx
@ -10,6 +8,7 @@ jmx
etc/jetty-jmx-remote.xml
[ini-template]
# tag::documentation[]
## The host/address to bind the RMI server to.
# jetty.jmxremote.rmiserverhost=localhost
@ -21,3 +20,7 @@ etc/jetty-jmx-remote.xml
## The port the RMI registry listens to.
# jetty.jmxremote.rmiregistryport=1099
## The host name exported in the RMI stub.
-Djava.rmi.server.hostname=localhost
# end::documentation[]

View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~
~ ========================================================================
~ Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
~
~ This program and the accompanying materials are made available under
~ the terms of the Eclipse Public License 2.0 which is available at
~ https://www.eclipse.org/legal/epl-2.0
~
~ This Source Code may also be made available under the following
~ Secondary Licenses when the conditions for such availability set
~ forth in the Eclipse Public License, v. 2.0 are satisfied:
~ the Apache License v2.0 which is available at
~ https://www.apache.org/licenses/LICENSE-2.0
~
~ SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
~ ========================================================================
~
-->
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">
<Configure>
<Ref refid="JMXConnectorServer">
<Call name="putAttribute">
<Arg>jmx.remote.x.password.file</Arg>
<Arg>etc/jmxremote.password</Arg>
</Call>
<Call name="putAttribute">
<Arg>jmx.remote.x.access.file</Arg>
<Arg>etc/jmxremote.access</Arg>
</Call>
</Ref>
</Configure>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~
~ ========================================================================
~ Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
~
~ This program and the accompanying materials are made available under
~ the terms of the Eclipse Public License 2.0 which is available at
~ https://www.eclipse.org/legal/epl-2.0
~
~ This Source Code may also be made available under the following
~ Secondary Licenses when the conditions for such availability set
~ forth in the Eclipse Public License, v. 2.0 are satisfied:
~ the Apache License v2.0 which is available at
~ https://www.apache.org/licenses/LICENSE-2.0
~
~ SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
~ ========================================================================
~
-->
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">
<Configure>
<Ref refid="JMXConnectorServer">
<Set name="sslContextFactory">
<Ref refid="sslContextFactory" />
</Set>
</Ref>
</Configure>

View File

@ -0,0 +1,4 @@
# The file format is: <username> <permission>
# Permissions can be either of these 2 tokens: readonly | readwrite
# username readonly

View File

@ -0,0 +1,3 @@
# The file format is: <username> <password>
# username password

View File

@ -1,7 +1,5 @@
# DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[description]
Enables JMX instrumentation for server beans and enables JMX agent.
Enables local JMX support for Jetty components.
[depend]
server
@ -11,4 +9,3 @@ lib/jetty-jmx-${jetty.version}.jar
[xml]
etc/jetty-jmx.xml

View File

@ -55,7 +55,7 @@ import org.slf4j.LoggerFactory;
* <li>participates in the {@code Server} lifecycle</li>
* <li>starts the RMI registry if not there already</li>
* <li>allows to bind the RMI registry and the RMI server to the loopback interface</li>
* <li>makes it easy to use TLS for the JMX communication</li>
* <li>makes it easy to use TLS for the RMI communication</li>
* </ul>
*/
public class ConnectorServer extends AbstractLifeCycle
@ -65,8 +65,8 @@ public class ConnectorServer extends AbstractLifeCycle
private JMXServiceURL _jmxURL;
private final Map<String, Object> _environment;
private final String _objectName;
private final SslContextFactory.Server _sslContextFactory;
private String _objectName;
private SslContextFactory.Server _sslContextFactory;
private int _registryPort;
private int _rmiPort;
private JMXConnectorServer _connectorServer;
@ -76,41 +76,92 @@ public class ConnectorServer extends AbstractLifeCycle
* Constructs a ConnectorServer
*
* @param serviceURL the address of the new ConnectorServer
* @param name object name string to be assigned to ConnectorServer bean
* @param objectName object name string to be assigned to ConnectorServer bean
*/
public ConnectorServer(JMXServiceURL serviceURL, String name)
public ConnectorServer(JMXServiceURL serviceURL, String objectName)
{
this(serviceURL, null, name);
this(serviceURL, null, objectName);
}
/**
* Constructs a ConnectorServer
*
* @param svcUrl the address of the new ConnectorServer
* @param serviceURL the address of the new ConnectorServer
* @param environment a set of attributes to control the new ConnectorServer's behavior.
* This parameter can be null. Keys in this map must
* be Strings. The appropriate type of each associated value depends on
* the attribute. The contents of environment are not changed by this call.
* @param name object name string to be assigned to ConnectorServer bean
* @param objectName object name string to be assigned to ConnectorServer bean
*/
public ConnectorServer(JMXServiceURL svcUrl, Map<String, ?> environment, String name)
public ConnectorServer(JMXServiceURL serviceURL, Map<String, ?> environment, String objectName)
{
this(svcUrl, environment, name, null);
this(serviceURL, environment, objectName, null);
}
public ConnectorServer(JMXServiceURL svcUrl, Map<String, ?> environment, String name, SslContextFactory.Server sslContextFactory)
/**
* Constructs a ConnectorServer
*
* @param serviceURL the address of the new ConnectorServer
* @param environment a set of attributes to control the new ConnectorServer's behavior.
* This parameter can be null. Keys in this map must
* be Strings. The appropriate type of each associated value depends on
* the attribute. The contents of environment are not changed by this call.
* @param objectName object name string to be assigned to ConnectorServer bean
* @param sslContextFactory the SslContextFactory.Server to use for secure communication
*/
public ConnectorServer(JMXServiceURL serviceURL, Map<String, ?> environment, String objectName, SslContextFactory.Server sslContextFactory)
{
this._jmxURL = svcUrl;
this._jmxURL = serviceURL;
this._environment = environment == null ? new HashMap<>() : new HashMap<>(environment);
this._objectName = name;
this._objectName = objectName;
this._sslContextFactory = sslContextFactory;
}
/**
* @return the JMXServiceURL of this ConnectorServer
*/
public JMXServiceURL getAddress()
{
return _jmxURL;
}
/**
* Puts an attribute into the environment Map.
*
* @param name the attribute name
* @param value the attribute value
*/
public void putAttribute(String name, Object value)
{
_environment.put(name, value);
}
/**
* @return the ObjectName of this ConnectorServer
*/
public String getObjectName()
{
return _objectName;
}
/**
* @param objectName the ObjectName of this ConnectorServer
*/
public void setObjectName(String objectName)
{
_objectName = objectName;
}
public SslContextFactory.Server getSslContextFactory()
{
return _sslContextFactory;
}
public void setSslContextFactory(SslContextFactory.Server sslContextFactory)
{
_sslContextFactory = sslContextFactory;
}
@Override
public void doStart() throws Exception
{
@ -119,7 +170,7 @@ public class ConnectorServer extends AbstractLifeCycle
{
if (!_environment.containsKey(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE))
_environment.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, new JMXRMIServerSocketFactory(_jmxURL.getHost(), port -> _rmiPort = port));
if (_sslContextFactory != null)
if (getSslContextFactory() != null)
{
SslRMIClientSocketFactory csf = new SslRMIClientSocketFactory();
if (!_environment.containsKey(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE))
@ -147,7 +198,7 @@ public class ConnectorServer extends AbstractLifeCycle
MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
_connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(_jmxURL, _environment, mbeanServer);
mbeanServer.registerMBean(_connectorServer, new ObjectName(_objectName));
mbeanServer.registerMBean(_connectorServer, new ObjectName(getObjectName()));
_connectorServer.start();
String rmiHost = normalizeHost(_jmxURL.getHost());
// If _rmiPort is still zero, it's using the same port as the RMI registry.
@ -166,7 +217,7 @@ public class ConnectorServer extends AbstractLifeCycle
ShutdownThread.deregister(this);
_connectorServer.stop();
MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
mbeanServer.unregisterMBean(new ObjectName(_objectName));
mbeanServer.unregisterMBean(new ObjectName(getObjectName()));
stopRegistry();
}

View File

@ -1,55 +1,50 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">
<?xml version="1.0"?><!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">
<!-- ============================================================= -->
<!-- SSL ContextFactory configuration -->
<!-- ============================================================= -->
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<Call name="addBean">
<Arg>
<New id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory$Server">
<Set name="Provider" property="jetty.sslContext.provider" />
<Set name="KeyStorePath"><Property name="jetty.base" default="." />/<Property name="jetty.sslContext.keyStorePath" default="etc/keystore.p12" /></Set>
<Set name="KeyStorePassword"><Property name="jetty.sslContext.keyStorePassword" /></Set>
<Set name="KeyStoreType" property="jetty.sslContext.keyStoreType" />
<Set name="KeyStoreProvider" property="jetty.sslContext.keyStoreProvider" />
<Set name="KeyManagerPassword"><Property name="jetty.sslContext.keyManagerPassword" /></Set>
<Set name="TrustStorePath"><Property name="jetty.base" default="." />/<Property name="jetty.sslContext.trustStorePath" default="etc/keystore.p12" /></Set>
<Set name="TrustStorePassword" property="jetty.sslContext.trustStorePassword" />
<Set name="TrustStoreType" property="jetty.sslContext.trustStoreType" />
<Set name="TrustStoreProvider" property="jetty.sslContext.trustStoreProvider" />
<Set name="EndpointIdentificationAlgorithm" property="jetty.sslContext.endpointIdentificationAlgorithm" />
<Set name="NeedClientAuth" property="jetty.sslContext.needClientAuth" />
<Set name="WantClientAuth" property="jetty.sslContext.wantClientAuth" />
<Set name="useCipherSuitesOrder" property="jetty.sslContext.useCipherSuitesOrder" />
<Set name="sslSessionCacheSize" property="jetty.sslContext.sslSessionCacheSize" />
<Set name="sslSessionTimeout" property="jetty.sslContext.sslSessionTimeout" />
<Set name="RenegotiationAllowed" property="jetty.sslContext.renegotiationAllowed" />
<Set name="RenegotiationLimit" property="jetty.sslContext.renegotiationLimit" />
<Set name="SniRequired" property="jetty.sslContext.sniRequired" />
<!--
To configure Includes / Excludes for Cipher Suites or Protocols see tweak-ssl.xml example at
https://www.eclipse.org/jetty/documentation/current/configuring-ssl.html#configuring-sslcontextfactory-cipherSuites
-->
<Configure id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory$Server">
<Set name="Provider" property="jetty.sslContext.provider"/>
<Set name="KeyStorePath"><Property name="jetty.base" default="." />/<Property name="jetty.sslContext.keyStorePath" default="etc/keystore.p12"/></Set>
<Set name="KeyStorePassword"><Property name="jetty.sslContext.keyStorePassword"/></Set>
<Set name="KeyStoreType" property="jetty.sslContext.keyStoreType"/>
<Set name="KeyStoreProvider" property="jetty.sslContext.keyStoreProvider"/>
<Set name="KeyManagerPassword"><Property name="jetty.sslContext.keyManagerPassword"/></Set>
<Set name="TrustStorePath"><Property name="jetty.base" default="." />/<Property name="jetty.sslContext.trustStorePath" default="etc/keystore.p12"/></Set>
<Set name="TrustStorePassword" property="jetty.sslContext.trustStorePassword"/>
<Set name="TrustStoreType" property="jetty.sslContext.trustStoreType"/>
<Set name="TrustStoreProvider" property="jetty.sslContext.trustStoreProvider"/>
<Set name="EndpointIdentificationAlgorithm" property="jetty.sslContext.endpointIdentificationAlgorithm"/>
<Set name="NeedClientAuth" property="jetty.sslContext.needClientAuth"/>
<Set name="WantClientAuth" property="jetty.sslContext.wantClientAuth"/>
<Set name="useCipherSuitesOrder" property="jetty.sslContext.useCipherSuitesOrder"/>
<Set name="sslSessionCacheSize" property="jetty.sslContext.sslSessionCacheSize"/>
<Set name="sslSessionTimeout" property="jetty.sslContext.sslSessionTimeout"/>
<Set name="RenegotiationAllowed" property="jetty.sslContext.renegotiationAllowed"/>
<Set name="RenegotiationLimit" property="jetty.sslContext.renegotiationLimit"/>
<Set name="SniRequired" property="jetty.sslContext.sniRequired"/>
<!-- Example of how to configure a PKIX Certificate Path revocation Checker
<Call id="pkixPreferCrls" class="java.security.cert.PKIXRevocationChecker$Option" name="valueOf"><Arg>PREFER_CRLS</Arg></Call>
<Call id="pkixSoftFail" class="java.security.cert.PKIXRevocationChecker$Option" name="valueOf"><Arg>SOFT_FAIL</Arg></Call>
<Call id="pkixNoFallback" class="java.security.cert.PKIXRevocationChecker$Option" name="valueOf"><Arg>NO_FALLBACK</Arg></Call>
<Call class="java.security.cert.CertPathBuilder" name="getInstance">
<Arg>PKIX</Arg>
<Call id="pkixRevocationChecker" name="getRevocationChecker">
<Call name="setOptions">
<Arg>
<Call class="java.util.EnumSet" name="of">
<Arg><Ref refid="pkixPreferCrls"/></Arg>
<Arg><Ref refid="pkixSoftFail"/></Arg>
<Arg><Ref refid="pkixNoFallback"/></Arg>
<!-- Example of how to configure a PKIX Certificate Path revocation Checker
<Call id="pkixPreferCrls" class="java.security.cert.PKIXRevocationChecker$Option" name="valueOf"><Arg>PREFER_CRLS</Arg></Call>
<Call id="pkixSoftFail" class="java.security.cert.PKIXRevocationChecker$Option" name="valueOf"><Arg>SOFT_FAIL</Arg></Call>
<Call id="pkixNoFallback" class="java.security.cert.PKIXRevocationChecker$Option" name="valueOf"><Arg>NO_FALLBACK</Arg></Call>
<Call class="java.security.cert.CertPathBuilder" name="getInstance">
<Arg>PKIX</Arg>
<Call id="pkixRevocationChecker" name="getRevocationChecker">
<Call name="setOptions">
<Arg>
<Call class="java.util.EnumSet" name="of">
<Arg><Ref refid="pkixPreferCrls"/></Arg>
<Arg><Ref refid="pkixSoftFail"/></Arg>
<Arg><Ref refid="pkixNoFallback"/></Arg>
</Call>
</Arg>
</Call>
</Call>
</Arg>
</Call>
</Call>
</Call>
<Set name="PkixCertPathChecker"><Ref refid="pkixRevocationChecker"/></Set>
-->
</New>
</Arg>
</Call>
<Set name="PkixCertPathChecker"><Ref refid="pkixRevocationChecker"/></Set>
-->
</Configure>

View File

@ -1,12 +1,11 @@
# DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[description]
Enables the Proxy Protocol on the HTTP Connector.
http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt
This allows a proxy operating in TCP mode to
transport details of the proxied connection to
the server.
Both V1 and V2 versions of the protocol are supported.
Enables PROXY Protocol (https://www.haproxy.org/download/2.1/doc/proxy-protocol.txt)
support on the clear-text connector.
Both versions V1 and V2 of the PROXY protocol are supported.
The PROXY protocol allows a proxy server to send transport
details of the proxied connection to the Jetty server, so that
applications can transparently obtain transport information
of remote clients as if there was no proxy server.
[depend]
http

View File

@ -48,7 +48,7 @@ public class StatisticsHandler extends HandlerWrapper implements Graceful
{
private static final Logger LOG = LoggerFactory.getLogger(StatisticsHandler.class);
private final AtomicLong _statsStartedAt = new AtomicLong();
private volatile Shutdown _shutdown;
private final Shutdown _shutdown;
private final CounterStatistic _requestStats = new CounterStatistic();
private final SampleStatistic _requestTimeStats = new SampleStatistic();
@ -92,27 +92,33 @@ public class StatisticsHandler extends HandlerWrapper implements Graceful
@Override
public void onComplete(AsyncEvent event)
{
HttpChannelState state = ((AsyncContextEvent)event).getHttpChannelState();
Request request = state.getBaseRequest();
final long elapsed = System.currentTimeMillis() - request.getTimeStamp();
long numRequests = _requestStats.decrement();
Request request = ((AsyncContextEvent)event).getHttpChannelState().getBaseRequest();
long elapsed = System.currentTimeMillis() - request.getTimeStamp();
_requestStats.decrement();
_requestTimeStats.record(elapsed);
updateResponse(request);
_asyncWaitStats.decrement();
if (numRequests == 0 && _gracefulShutdownWaitsForRequests)
{
Shutdown shutdown = _shutdown;
if (shutdown != null)
shutdown.check();
}
if (_shutdown.isShutdown())
_shutdown.check();
}
};
public StatisticsHandler()
{
_shutdown = new Shutdown(this)
{
@Override
public boolean isShutdownDone()
{
if (_gracefulShutdownWaitsForRequests)
return _requestStats.getCurrent() == 0;
else
return _dispatchedStats.getCurrent() == 0;
}
};
}
/**
* Resets the current request statistics.
*/
@ -174,8 +180,7 @@ public class StatisticsHandler extends HandlerWrapper implements Graceful
final long now = System.currentTimeMillis();
final long dispatched = now - start;
long numRequests = -1;
long numDispatches = _dispatchedStats.decrement();
_dispatchedStats.decrement();
_dispatchedTimeStats.record(dispatched);
if (state.isInitial())
@ -187,19 +192,14 @@ public class StatisticsHandler extends HandlerWrapper implements Graceful
}
else
{
numRequests = _requestStats.decrement();
_requestStats.decrement();
_requestTimeStats.record(dispatched);
updateResponse(baseRequest);
}
}
Shutdown shutdown = _shutdown;
if (shutdown != null)
{
response.flushBuffer();
if (_gracefulShutdownWaitsForRequests ? (numRequests == 0) : (numDispatches == 0))
shutdown.check();
}
if (_shutdown.isShutdown())
_shutdown.check();
}
}
@ -230,8 +230,11 @@ public class StatisticsHandler extends HandlerWrapper implements Graceful
}
}
else
{
// will fall through to not found handler
_responses4xx.increment();
}
_responsesTotalBytes.add(response.getContentCount());
}
@ -240,17 +243,7 @@ public class StatisticsHandler extends HandlerWrapper implements Graceful
{
if (getHandler() == null)
throw new IllegalStateException("StatisticsHandler has no Wrapped Handler");
_shutdown = new Shutdown(this)
{
@Override
public boolean isShutdownDone()
{
if (_gracefulShutdownWaitsForRequests)
return _requestStats.getCurrent() == 0;
else
return _dispatchedStats.getCurrent() == 0;
}
};
_shutdown.cancel();
super.doStart();
statsReset();
}
@ -258,8 +251,8 @@ public class StatisticsHandler extends HandlerWrapper implements Graceful
@Override
protected void doStop() throws Exception
{
_shutdown.cancel();
super.doStop();
_shutdown = null;
}
/**
@ -610,17 +603,13 @@ public class StatisticsHandler extends HandlerWrapper implements Graceful
@Override
public CompletableFuture<Void> shutdown()
{
Shutdown shutdown = _shutdown;
if (shutdown == null)
return CompletableFuture.completedFuture(null);
return shutdown.shutdown();
return _shutdown.shutdown();
}
@Override
public boolean isShutdown()
{
Shutdown shutdown = _shutdown;
return shutdown == null || shutdown.isShutdown();
return _shutdown.isShutdown();
}
@Override

View File

@ -34,6 +34,7 @@ import java.util.Objects;
import java.util.Set;
import java.util.Stack;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import jakarta.servlet.GenericServlet;
import jakarta.servlet.MultipartConfigElement;
@ -588,7 +589,7 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
servlet = getInstance();
if (servlet == null)
servlet = newInstance();
if (servlet instanceof javax.servlet.SingleThreadModel)
if (servlet instanceof SingleThreadModel)
{
predestroyServlet(servlet);
servlet = new SingleThreadedWrapper();

View File

@ -78,7 +78,8 @@ public interface Graceful
public CompletableFuture<Void> shutdown()
{
if (_done.get() == null)
_done.compareAndSet(null, new CompletableFuture<Void>()
{
_done.compareAndSet(null, new CompletableFuture<>()
{
@Override
public String toString()
@ -86,6 +87,7 @@ public interface Graceful
return String.format("Shutdown<%s>@%x", _component, hashCode());
}
});
}
CompletableFuture<Void> done = _done.get();
check();
return done;
@ -110,6 +112,15 @@ public interface Graceful
done.complete(null);
}
public void cancel()
{
CompletableFuture<Void> done = _done.get();
if (done != null && !done.isDone())
done.cancel(true);
_done.set(null);
}
/**
* @return True if the component is shutdown and has no remaining load.
*/

View File

@ -43,7 +43,7 @@
<junit.version>5.7.0</junit.version>
<maven.version>3.6.3</maven.version>
<maven.resolver.version>1.6.1</maven.resolver.version>
<weld.version>3.1.5.Final</weld.version>
<weld.version>4.0.0.Beta5</weld.version>
<jboss.logging.version>3.4.1.Final</jboss.logging.version>
<jetty.perf-helper.version>1.0.6</jetty.perf-helper.version>
<ant.version>1.10.9</ant.version>