Configure HTTPS for jetty-maven-plugin 9.0.x
For the impatient
If you do not want to know why it does not work and how I fixed it, just jump to the quick fix!
jetty-maven-plugin 9.0.x breaks the HTTPS-Connector
With Jetty 9.0.x the configuration of the jetty-maven-plugin
(formaly known as maven-jetty-plugin
) has changed dramatically. Since then, it is no more possible to configure a HTTPS-Connector in the plugin easily. Normally, connecting your development-container via HTTPS was not often necessary. But since Snowden, encryption is on everybodys mind. And so, testing the encrypted part of your webapp becomes more and more important.
Why it is “broken” in jetty-maven-plugin
9.0.x
A bug-report stats, that
Since the constructor signature changed for Connectors in jetty-9 to require the Server instance to be passed into it, it is no longer possible to configure Connectors directly with the plugin (because maven requires no-arg constructor for any <configuration> elements).
The documentation includes an example, how to configure a HTTPS Connector with the help of a jetty.xml
-file. But unfortunatly, this example is broken. Jetty refuses to start with the following error: [ERROR] Failed to execute goal org.eclipse.jetty:jetty-maven-plugin:9.0.5.v20130815:run (default-cli) on project FOOBAR: Failure: Unknown configuration type: New in org.eclipse.jetty.xml.XmlConfiguration@4809f93a -> [Help 1]
.
Get HTTPS running again
So, here is, what you have to do to fix this broken example: the content shown for the file jetty.xml
in the example is wrong. It has to look like the other example-files. That is, ith has to start with a <Configure>
-tag. The corrected content of the file looks like this:
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
<!-- ============================================================= -->
<!-- Configure the Http Configuration -->
<!-- ============================================================= -->
<Configure id="httpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
<Set name="secureScheme">https</Set>
<Set name="securePort"><Property name="jetty.secure.port" default="8443" /></Set>
<Set name="outputBufferSize">32768</Set>
<Set name="requestHeaderSize">8192</Set>
<Set name="responseHeaderSize">8192</Set>
<Set name="sendServerVersion">true</Set>
<Set name="sendDateHeader">false</Set>
<Set name="headerCacheSize">512</Set>
<!-- Uncomment to enable handling of X-Forwarded- style headers
<Call name="addCustomizer">
<Arg><New class="org.eclipse.jetty.server.ForwardedRequestCustomizer"/></Arg>
</Call>
-->
</Configure>
But it’s not running!
If you are getting the error [ERROR] Failed to execute goal org.eclipse.jetty:jetty-maven-plugin:9.0.5.v20130815:run (default-cli) on project FOOBAR: Failure: etc/jetty.keystore (file or directory not found) -> [Help 1]
now, this is because you have to create/get a certificate for your HTTPS-Connector. For development, a selfsigned certificate is sufficient. You can easily create one like back in the good old maven-jetty-plugin
-times, with this command: keytool -genkey -alias jetty -keyalg RSA -keystore src/test/resources/jetty.keystore -storepass secret -keypass secret -dname "CN=localhost"
. Just be sure, to change the example file jetty-ssl.xml
, to reflect the path to your new keystore file and password. Your jetty-ssl.xml
should look like:
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
<!-- ============================================================= -->
<!-- Configure a TLS (SSL) Context Factory -->
<!-- This configuration must be used in conjunction with jetty.xml -->
<!-- and either jetty-https.xml or jetty-spdy.xml (but not both) -->
<!-- ============================================================= -->
<Configure id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory">
<Set name="KeyStorePath"><Property name="jetty.base" default="." />/<Property name="jetty.keystore" default="src/test/resources/jetty.keystore"/></Set>
<Set name="KeyStorePassword"><Property name="jetty.keystore.password" default="secret"/></Set>
<Set name="KeyManagerPassword"><Property name="jetty.keymanager.password" default="secret"/></Set>
<Set name="TrustStorePath"><Property name="jetty.base" default="." />/<Property name="jetty.truststore" default="src/test/resources/jetty.keystore"/></Set>
<Set name="TrustStorePassword"><Property name="jetty.truststore.password" default="secret"/></Set>
<Set name="EndpointIdentificationAlgorithm"></Set>
<Set name="ExcludeCipherSuites">
<Array type="String">
<Item>SSL_RSA_WITH_DES_CBC_SHA</Item>
<Item>SSL_DHE_RSA_WITH_DES_CBC_SHA</Item>
<Item>SSL_DHE_DSS_WITH_DES_CBC_SHA</Item>
<Item>SSL_RSA_EXPORT_WITH_RC4_40_MD5</Item>
<Item>SSL_RSA_EXPORT_WITH_DES40_CBC_SHA</Item>
<Item>SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA</Item>
<Item>SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA</Item>
</Array>
</Set>
<!-- =========================================================== -->
<!-- Create a TLS specific HttpConfiguration based on the -->
<!-- common HttpConfiguration defined in jetty.xml -->
<!-- Add a SecureRequestCustomizer to extract certificate and -->
<!-- session information -->
<!-- =========================================================== -->
<New id="sslHttpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
<Arg><Ref refid="httpConfig"/></Arg>
<Call name="addCustomizer">
<Arg><New class="org.eclipse.jetty.server.SecureRequestCustomizer"/></Arg>
</Call>
</New>
</Configure>
But it’s still not running!
Unless you are running mvn jetty:run
as root
, you should see another error now: [ERROR] Failed to execute goal org.eclipse.jetty:jetty-maven-plugin:9.0.5.v20130815:run (default-cli) on project FOOBAR: Failure: Permission denied -> [Help 1]
. This is, because the ports are set to the numbers 80
and 443
of the privileged port-range.
You have to change jetty-http.xml
like this:
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
<!-- ============================================================= -->
<!-- Configure the Jetty Server instance with an ID "Server" -->
<!-- by adding a HTTP connector. -->
<!-- This configuration must be used in conjunction with jetty.xml -->
<!-- ============================================================= -->
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<!-- =========================================================== -->
<!-- Add a HTTP Connector. -->
<!-- Configure an o.e.j.server.ServerConnector with a single -->
<!-- HttpConnectionFactory instance using the common httpConfig -->
<!-- instance defined in jetty.xml -->
<!-- -->
<!-- Consult the javadoc of o.e.j.server.ServerConnector and -->
<!-- o.e.j.server.HttpConnectionFactory for all configuration -->
<!-- that may be set here. -->
<!-- =========================================================== -->
<Call name="addConnector">
<Arg>
<New class="org.eclipse.jetty.server.ServerConnector">
<Arg name="server"><Ref refid="Server" /></Arg>
<Arg name="factories">
<Array type="org.eclipse.jetty.server.ConnectionFactory">
<Item>
<New class="org.eclipse.jetty.server.HttpConnectionFactory">
<Arg name="config"><Ref refid="httpConfig" /></Arg>
</New>
</Item>
</Array>
</Arg>
<Set name="host"><Property name="jetty.host" /></Set>
<Set name="port"><Property name="jetty.port" default="8080" /></Set>
<Set name="idleTimeout"><Property name="http.timeout" default="30000"/></Set>
</New>
</Arg>
</Call>
</Configure>
… and jetty-https.xml
like this:
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
<!-- ============================================================= -->
<!-- Configure a HTTPS connector. -->
<!-- This configuration must be used in conjunction with jetty.xml -->
<!-- and jetty-ssl.xml. -->
<!-- ============================================================= -->
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<!-- =========================================================== -->
<!-- Add a HTTPS Connector. -->
<!-- Configure an o.e.j.server.ServerConnector with connection -->
<!-- factories for TLS (aka SSL) and HTTP to provide HTTPS. -->
<!-- All accepted TLS connections are wired to a HTTP connection.-->
<!-- -->
<!-- Consult the javadoc of o.e.j.server.ServerConnector, -->
<!-- o.e.j.server.SslConnectionFactory and -->
<!-- o.e.j.server.HttpConnectionFactory for all configuration -->
<!-- that may be set here. -->
<!-- =========================================================== -->
<Call id="httpsConnector" name="addConnector">
<Arg>
<New class="org.eclipse.jetty.server.ServerConnector">
<Arg name="server"><Ref refid="Server" /></Arg>
<Arg name="factories">
<Array type="org.eclipse.jetty.server.ConnectionFactory">
<Item>
<New class="org.eclipse.jetty.server.SslConnectionFactory">
<Arg name="next">http/1.1</Arg>
<Arg name="sslContextFactory"><Ref refid="sslContextFactory"/></Arg>
</New>
</Item>
<Item>
<New class="org.eclipse.jetty.server.HttpConnectionFactory">
<Arg name="config"><Ref refid="sslHttpConfig"/></Arg>
</New>
</Item>
</Array>
</Arg>
<Set name="host"><Property name="jetty.host" /></Set>
<Set name="port"><Property name="https.port" default="8443" /></Set>
<Set name="idleTimeout"><Property name="https.timeout" default="30000"/></Set>
</New>
</Arg>
</Call>
</Configure>
Now, it should be running, but…
That is all much to complex. I just want a quick fix to get it running!
So, now it is working. But you still have to clutter your project with several files and avoid some pitfalls (belive me or not: if you put the filenames in the <jettyXml>
-tag of your pom.xml
on separate lines, jetty won’t start!). Last but not least, the HTTP-Connector will stop working, if you forget to add the jetty-http.xml
, that is mentioned at the end of the example.
Because of that, I’ve created a simple 6-step quick-fix-guide to get the HTTPS-Connector of the jetty-maven-plugin
running.
Quick Fix
- Download jetty.xml or copy it from above and place it in
src/test/resources/jetty.xml
- Download jetty-http.xml or copy it from above and place it in
src/test/resources/jetty-http.xml
- Download jetty-ssl.xml or copy it from above and place it in
src/test/resources/jetty-ssl.xml
- Download jetty-https.xml or copy it from above and place it in
src/test/resources/jetty-https.xml
- Download jetty.keystore or generate it with the command keytool-command from above and place it in
src/test/resources/jetty.keystore
- Update the configuration of the
jetty-maven-plugin
in yourpom.xml
to include the XML-configurationfiles. But be aware, the ordering of the files is important and there should be no newlines inbetween. You have been warned! It should look like:<plugin> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> <configuration> <jettyXml> ${project.basedir}/src/test/resources/jetty.xml,${project.basedir}/src/test/resources/jetty-http.xml,${project.basedir}/src/test/resources/jetty-ssl.xml,${project.basedir}/src/test/resources/jetty-https.xml </jettyXml> </configuration> </plugin>
That’s it. You should be done!
Do you have a Patreon account? How can I buy you a coffee! This had to have taken a long time to configure. Thank you.