Closed openfirmware closed 6 years ago
I have been working on this issue this week and have learned some things.
I don't think this is a workable solution as it would be fragile and require you to use specific Jetty versions (and its according servlet API version) for different versions of Tomcat (or whichever container runner application). For example, there would have to be a version for Tomcat 6 (servlet API 2.5), Tomcat 7 (servlet API 3.0), Tomcat 8/8.5 (servlet API 3.1), Tomcat 9.0 (servlet API 4.0). This adds a lot of overhead for the system administrator who wants to install this ETS in their TEAM Engine.
Additionally, older versions of Jetty have different levels of TLS and cipher suite security (i.e. deprecated cipher lists). This could complicate testing modern secure clients which may not connect to older versions of Jetty.
This also will depend on the system administrator, and has the same issue of needing different Jetty versions for different Tomcat versions. There is no Jetty version currently released that uses Servlet API 4.0, so does that mean the ETS cannot be used with Tomcat 9?
I think there might be something in MonitorServlet or similar classes that could be used to create custom test session endpoints for secure clients. However I can't find any documentation on how to use these.
There is another potential solution I alluded to, which is using dynamic class loaders in Java to load Jetty's servlet API for this ETS, and then restoring the class loader when finished. I found some references to this being possible:
I am not experienced enough with Java to fully understand this, although I am giving it a shot as I think it will be the fastest way to get TEAM Engine support working.
I am working on the last option, as I don't think I have enough time to learn the internals of TEAM Engine for option C. If I can't get it working then I will have to explain in the ER what the current shortcomings in TEAM Engine and ETS are for client testing suites, and how we can potentially move forward with improving support.
Two more options:
There was a thread on using this somewhere in the TEAM Engine repository. Maybe this could be implemented in just this ETS, and not need changes in TE. I haven't used OSGi so I don't know how much work this is. Kind of similar to Option D, but is more formalized.
Could create a separate java process for the test server, and use some sort of inter-process communication to setup and teardown the test server and endpoints for test sessions. Could be a lot of work. There might be security implications in running a separate process, as some OS security systems may need special configuration (I am thinking of AppArmor).
The Maven Shade plugin offers class renaming and relocation, which might be enough to avoid the servlet api version conflict.
The Maven Shade plugin seems to be working, I have some code on a branch.
I forked teamengine-docker and created a new entry for ets-security-client10
and have been using that to test locally. I had to modify the Dockerfile to add an extra task which extracts the sample Java Keystore file, so that the ETS has one. A better procedure for the TEAM Engine system administrator will be developed where they can set up the keystore details when they install the ETS.
The Shade plugin method works as far as running a new test session as WMS 1.1.1, and the Docker TEAM Engine console lists the test session endpoint (should be exposed in the browser though). I modified the docker-run command to open port 10080 for the ETS. Connecting to that endpoint using curl fails though with an SSL handshake error:
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 10080 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
* CAfile: /etc/ssl/cert.pem
CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to 127.0.0.1:10080
* Closing connection 0
curl: (35) LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to 127.0.0.1:10080
I am looking into this now. Maybe the Java version in the Docker image is too old or doesn't have the right security ciphers?
I fixed the test run properties to run the Jetty server on 0.0.0.0
host, and tried to connect to that server inside the Docker container by starting bash instead of Tomcat, then starting Tomcat in the background and connecting with curl. Still fails, because the Jetty test server isn't actually started?
I brought up this issue during our CITE teleconference today, and Torsten asked me to clarify the versions being used here.
When I am testing the JAR or IDE, I am using:
Running as JAR/IDE is no problem. (If I have time, I would like to use Docker to automate testing the JAR process under different JDK versions, but I have to get this and a few other major items done first.)
For testing under TEAM Engine:
Right now when I run the ETS from TEAM Engine in Docker, the Docker console will print out the same test information as the JAR. This information contains the HTTP(S) endpoint for the test session, which I am trying to connect to from a test client (curl).
There are a few considerations for connecting to the ETS running in a Docker container, especially on a MacOS host, as the Docker container is running under a Linux VM which is running in MacOS. I was able to open ports to access TEAM Engine on port 8080, but accessing the ETS endpoint on port 10080 (the sample port I use in the test run properties) fails.
I have tried creating a second Docker container and connecting to the first container, and used nmap
to scan the ports that were open; only the two Tomcat ports were available and port 10080 was not open.
I also tried launching the TEAM Engine docker with an interactive bash session instead of the Catalina script, and then ran the Catalina script in the background. Then I could set up a test session, and try using curl
in the same container as the ETS, which should eliminate any firewall issues. This also fails and is what I am debugging now.
Found the issue. In the CTL script for TEAM Engine, wms-111
was being passed in as a test run property instead of wms111
. This caused the embedded Jetty server to issue a NPE, which was caught in a try/catch handler and no output was sent to the console.
I had set up Tomcat 7 with Eclipse and JDK 8 under MacOS, and was able to use that to debug the TestServer class in the ETS. (I will write up a short guide on how to set up that test environment, as there doesn't seem to be an existing guide.)
I also tested this fix with TEAM Engine running under Docker, and when the host is set to 0.0.0.0
and port 10080
is published by Docker, I could access the testing endpoint from the host machine.
There are a few things to clean up before I will merge in the fix to the master repository:
Our lab has set up a cloud instance that we are using for another Testbed 14 deliverable, and I will deploy TEAM Engine to that instance for demonstrating how to use a free HTTPS certificate from Let's Encrypt.
Using Maven Shade to "rename" a set of packages into namespaces that do not conflict with earlier versions of those libraries loaded by Tomcat is a working solution.
I created a local fork of teamengine-docker and added a sub-project for this test suite, and this has made it easier for me to deploy and test changes. A recent change in my commits caused the test session in TEAM Engine to fail after starting the test session; this only occurs with TEAM Engine and not when running the test suite under an IDE or as an executable JAR.
The console running the Docker container with TEAM Engine 5.3 has some clues:
The main two items are:
and
These are both caused by servlet-api 2.5 being loaded instead of servlet-api 3.1. The version of Jetty I am embedding (
9.4.11.v20180605
) corresponds to that version of the servlet-api. Tomcat however loads servlet-api 2.5; I was able to copy the tomcat directory out of the Docker container and found this version of the servlet-api in tomcat'slib
directory.From what I found online regarding this first message, the common solution is to set the servlet-api as "provided" in Maven to have the existing version of the library to be used instead. The second error message is a very common problem, although I haven't found anyone else with the "embedded server inside a Tomcat WAR" scenario.
The real problem is the mismatch in versions providing different APIs to servlet. I have a few potential solutions which I would like to share, as I may be missing something that Java might be able to do to handle this. (Can Java handle two versions of a library? Node.js does this, but that is a way different implementation.)
The first one is probably easiest to get running. Downside is that this is an old and unsupported version, and the API may change and affect the ETS code.
The second is outside of this ETS and I am not sure about how strong of requirements we can have for TEAM Engine/Tomcat. It may also require different ETS versions for different Tomcat versions, each with a different servlet-api.
The third one will require more coding and more testing as there are more code paths.
I will be working on the ETS implementation for the JAR/IDE interfaces first and once those are stable I will come back and fix the TEAM Engine interface (and this issue). If anyone has any suggestions, please let me know!