How to make Jetty load webdefault.xml when it runs in OSGi? - jetty

I'm running a Jetty 8.1.12 server within an OSGi container thanks to jetty-osgi-boot as explained in Jetty 8 and Jetty 9 documentation
I want to configure the default webapp descriptor (etc/webdefault.xml). When I define jetty.home, jetty picks up etc/jetty.xml but it does not load etc/webdefault.xml
I do not want to rely on a configuration bundle (through the jetty.home.bundle system property) because I want the config easily modifiable.
I do not want to rely on the Jetty-defaultWebXmlFilePath MANIFEST header for the same reason, plus it would tie my webapp to jetty.
The jetty-osgi-boot bundle contains a jetty-deployer.xml configuration file with this commented-out chunk :
<!-- Providers of OSGi Apps -->
<Call name="addAppProvider">
<Arg>
<New class="org.eclipse.jetty.osgi.boot.OSGiAppProvider">
<Set name="defaultsDescriptor"><Property name="jetty.home" default="."/>/etc/webdefault.xml</Set>
...
which does not work because the OSGiAppProvider class does not exist anymore.
Is there any other way to configure the webdefaults.xml file location ?

Short answer : I could not have jetty 8.1.12 to load webdefaults.xml under OSGi.
After many hours of googling, source-reading and debugging, I came to these conclusions :
The Jetty-defaultWebXmlFilePath MANIFEST header did not work as expected. It could not resolve a bundle entry path, only a absolute file system path. An absolute FS path was not a realistic option.
Much of the configuration is hardcoded in ServerInstanceWrapper and the likes of BundleWebAppProvider so we cannot configure defaults descriptor location. This location ends up to the default, which is, IIRC, org/eclipse/jetty/webapp/webdefault.xml.
I resorted to patching jetty-osgi so that it can read some configuration and apply it to BundleWebAppProvider. FWIW this hack is available on github

Related

Is Jetty 9.4.43 is affected by the Log4j2 vulnerabilities : CVE-2021-44228 or CVE-2021-45046 or CVE-2021-45105?

We are using jetty9.4.43 in our application.
Logging modules not being used by default.
Can any one confirm whether jetty9.4.43 has any impact over CVE-2021-44228?
Update: Dec 18, 2021
There is a new Log4j CVE just issued.
https://logging.apache.org/log4j/2.x/security.html#CVE-2021-45105
Minimum recommended Log4j version is now 2.17.0.
Update: Dec 13, 2021
There is a new Log4J CVE issued.
https://access.redhat.com/security/cve/cve-2021-45046
Minimum recommended Log4j version is now 2.16.0
Original Text
Also covered at https://webtide.com/jetty-log4j2-exploit-cve-2021-44228/
Jetty has no direct dependency on log4j.
Jetty 9.x uses it's own logging framework StdErrLog, and has optional support for slf4j.
You, as a consumer of Jetty, can choose to use slf4j and then optionally take the next step and use log4j within that slf4j configuration.
So, while it's possible to use log4j 1.x or 2.x on Jetty 9.x, it's a decision that users choose to make, and it's up to the users to decide what they want to do. (Eg: upgrade to log4j 2.16.0 to satisfy both recent CVEs, or switch to a different logging framework like logback)
Waiting for a new release of Jetty is not necessary to address this CVE.
Also note that the log4j2 CVE does not impact users on Java 11.0.2 or newer, as the internal JVM property com.sun.jndi.ldap.object.trustURLCodebase is set to false by default starting with Java 11.0.2, which disables JNDI loading of classes from arbitrary URL code bases. (Users on Java 8 have more work than users on Java 11.0.2 or newer)
Eclipse Jetty Security Reports
All verified security reports for Eclipse Jetty can be found at ...
https://www.eclipse.org/jetty/security_reports.php
Github tracked and published advisories can be found at ...
https://github.com/eclipse/jetty.project/security/advisories?state=published

Is there a way to catch container-generated STDOUT within embedded Jetty Logback?

Situation is:
-> a homemade container app, using logback, configured with ConsoleAppender. Different loggers to specify log levels depending on package:
<logger name="com.mycompany.package1">
<level value="DEBUG"/>
</logger>
<logger name="com.mycompany.package2">
<level value="INFO"/>
</logger>
-> an embedded Jetty app, using logback, configured with RollingFileAppender.
I need both log outputs to be sent to the same rolling file, so I'm trying to catch the container STDOUT within the embedded Jetty app. Is there a way to do that? is it the wrong way to go about it?
NOTE: I have access to both logback.xml for editing.
If you have a logback configuration going to ConsoleAppender then don't attempt to catch output and log it again (you just created a loop).
Instead, just configure Jetty to use slf4j for its own events and NOT use the RolloverFileOutputStream or the console-capture module (from jetty-home).
The easiest way is to not do anything, the mere existence of slf4j-api-<ver>.jar in the server classpath is sufficient to make Jetty use slf4j to log its own events on.
In short, your server classpath needs:
slf4j-api-<ver>.jar
Your logback jars (probably logback-classic-<ver>.jar and logback-core-<ver>.jar)
A ${jetty.base}/resources/ directory on your classpath with 2 files:
a jetty-logging.properties with a single line org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.Slf4jLog
your logback configuration files. (eg: logback.xml)
Make sure you are not using Jetty's RollingFileOutputStream to capture System.out and/or System.err to a file.

Correct way to enable graceful shutdown in Jetty 9.3

I have been trying to use the StatisticsHandler to enable graceful shutdown in Jetty 9.3. But to my dismay, it does not seem to be that straight forward. First of all, let me explain my environment. I am using multiple jetty modules (gzip, server, servlets, jsp, jstl, etc.) and every module is instantiated by its corresponding .ini file in start.d directory. I have set stopTimeout to be 15000 and stopAtShutdown as true. (in same way as in default jetty.xml)
To enable StatisticsHandler i tried the following methods:
added stats.ini file in start.d directory and the contents of the file were as follows:
--module=stats
Even after adding the module and restarting jetty, when i stop jetty there is no graceful shutdown and it just stops immediately.
Then i tried adding the statistics handler in Jetty.xml as mentioned in the documentation. It was added as follows:
<Get id="oldhandler" name="handler" />
<Set name="handler">
<New id="StatsHandler" class="org.eclipse.jetty.server.handler.StatisticsHandler">
<Set name="handler"><Ref refid="oldhandler" /></Set>
</New>
</Set>
But even then just restarting jetty didn't solve my problem. Can someone guide me about what I am doing wrong, or what needs to be done to enable graceful shutdown in jetty.
Thanks in advance.
Graceful shutdown has nothing to do with StatisticsHandler (or its module), it's controlled by the org.eclipse.jetty.server.ShutdownMonitor object, and its interaction with the org.eclipse.jetty.server.Server instance.
The behavior of which is determined by the ${jetty.base} configuration and is initiated by the jetty-distribution's start.jar directly to the active ShutdownMonitor you previously configured on startup of the Server instance.

Web service's PostConstruct called before servlet context listener's contextInitialized

I need to migrate a web service application from Tomcat 6 (using JDK 1.5) to Tomcat 7 (using JDK 1.6) (actually testing on 7.0.27). The JAX-WS framework is Metro 2.1.
I'm using two ServletContextListeners:
"WebAppListener" : to initialize the application (configuration, setup of database connections...).
"com.sun.xml.ws.transport.http.servlet.WSServletContextListener": the Metro listener that creates the web services.
The order is important, because I need my web app fully initialized before the #PostConstruct method is called on my web service.
In Tomcat 6, this works marvelously:
INFO: Starting Servlet Engine: Apache Tomcat/6.0.36
mars 16, 2013 5:13:13 PM org.apache.catalina.startup.HostConfig deployWAR
INFO: Deploying web application archive WSWebApp.war
************************ IN WebAppListener.contextInitialized ***********************
************************ IN WSMyWebService.postConstruct ****************************
Exactly the same war however in Tomcat 7:
mars 16, 2013 6:45:24 PM org.apache.catalina.startup.HostConfig deployWAR
INFO: Deploying web application archive C:\home\tomcat\webapps\WSWebApp.war
************************ IN WSMyWebService.postConstruct ****************************
************************ IN WebAppListener.contextInitialized ***********************
I thought that the order in which the listener's are called is the order in which they appear in the web.xml?
Why this order has been changed in Tomcat 7? But more importantly: What do I need to do to get the "Tomcat6" order back?
Thanks.
The answer lies in a difference between Servlet spec 2.5 and Servlet spec 3.0.
In Servlet spec 2.5, the order in which listeners are called is defined by the order of their declaration in the deployment descriptor (web.xml):
SRV.10.3.3 Listener Registration.
The Web container creates an
instance of each listener class and registers it for event
notifications prior to the processing of the first request by the
application. The Web container registers the listener instances
according to the interfaces they implement and the order in which
they appear in the deployment descriptor. During Web application
execution, listeners are invoked in the order of their registration.
In Servlet spec 3.0, the order in which listeners are called is defined by the element <absolute-ordering> in the deployment descriptor (web.xml):
8.2.3 Assembling the descriptor from web.xml, webfragment.xml and annotations. ... c. Prior to this release of the specification,
context listeners were invoked in random order.
This is wrong IMHO, as stated above in the version 2.5 spec. :-)
As of Servlet 3.0,
the listeners are invoked in the order in which they are declared in
the web.xml as specified below: i. Implementations of
javax.servlet.ServletContextListener are invoked at their
contextInitialized method in the order in which they have been
declared, and at their contextDestroyed method in reverse order.
This doesn't work at all like you'd expect and is the source of my trouble, confusion and a lost weekend. ;-)
It's NOT the same ordering as before (2.5 spec)!
But there is more... (the AHA moment is near!)
8.2.2 Ordering of web.xml and web-fragment.xml
Since the specification allows the application configuration resources
to be composed of multiple configuration files (web.xml and
web-fragment.xml), discovered and loaded from several different
places in the application, the question of ordering must be
addressed.
...
Two cases must be considered to allow application configuration
resources to express their ordering preferences.
1. Absolute ordering: an <absolute-ordering> element in the web.xml. a. In this case, ordering preferences that would have been handled by
case 2 below must be ignored.
2. Relative ordering: an <ordering> element within the web-fragment.xml. a. A web-fragment.xml may have an <ordering>
element. If so, this element must contain zero or one <before>
element and zero or one <after> element. The meaning of these elements
is explained below.
So, in my case, I had two options:
Stick with version 2.5 : This works well on Tomcat 6 and 7, but is only moving problems to the future.
Migrate to version 3.0 of the spec and adjust my deployment descriptor accordingly:
Update the version and schema in the web-app element, of course:
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
Adding a <absolute-ordering> element that defines the order in which the listeners should be processed:
<absolute-ordering> <name>bootstrap</name><name>ws</name><others/></absolute-ordering>
<listener id="bootstrap">
<listener-class>lu.estiedi.ws.WebAppBootstrap</listener-class>
</listener>
<listener id="ws">
<listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class>
</listener>
Note the <others/> element : if it's not present, then the listeners that are not named will not be processed.
EDIT:
This doesn't actually solve the problem.
It went away yesterday at home, but this morning at work the solution didn't work. :-(
It looks like Metro is using a service provider ServletContainerInitializer, which are called before the Listeners.
If this is the way it's supposed to work, then the PosConstruct method is always called before the contextInitialized on Listeners.
Where do we initialise our application then, before the web services are created?
It is not about order of Listeners, it is about a new feature of servlets spec 3.0 and the fact that you are probably using a JAX-WS implementatios like METRO, I suppose.
In servlets spec 3.0 (chapter 8.2.4) there is a way to add 3rd party plugins or APIs to containers (Tomcat in this case), for example JAX-WS, JAX-RS, JSF, etc. implementations. It is also known ad SCI (javax.servlet.ServletContainerInitializer).
In short, METRO JAX-WS jars use this way so it is not mandatory to add listener (com.sun.xml.ws.transport.http.servlet.WSServletContextListener) and servlet configuration in your web.xml descriptor file. It uses sun-jaxws.xml file to list ws endpoints and instantiate ws classes before deployment of web application and execution, for example, of methods contextInitialized of listeners.
To avoid this, just follow instructions for avoiding SCI mechanism in Tomcat: How do I make Tomcat startup faster?
There exists an attribute on Context element, containerSciFilter. It can be used to disable container-provided features that are plugged into Tomcat via SCI API: WebSocket support (in Tomcat 7 and later), JSP support (in Tomcat 8 and later).
The class names to filter can be detected by looking into META-INF/services/javax.servlet.ServletContainerInitializer files in Tomcat JARs. For WebSocket support the name is org.apache.tomcat.websocket.server.WsSci, for JSP support the name is org.apache.jasper.servlet.JasperInitializer.
It worked for me with JAX-WS and it just uses web.xml config to deploy web services.

Setting Tomcat 7 sessionid and value to be identified via Hardware Load Balancing for session affinity

Although easily done from my perspective with IIS, I'm a total noob to Tomcat and have no idea how to set static values for cookie contents. Yes I've read the security implications and eventually will access via SSL so I'm not concerned. Plus I've read the Servlet 3.0 spec about not changing the value and I accept that.
In IIS I would simply set a HTTP Header named Set-Cookie with an arbitrary setting of WebServerSID and a value of 1001.
Then in the load balancer VIP containing this group of real servers, set the value WebServerSID at the VIP level, and for the first web server a cookie value of 1001 and so one for the remaining machines 1002 for server 2, 1003 for server 3.
This achieves session affinity via cookies until the client closes the browser.
How can this be done with Tomcat 7.0.22?
I see a great deal of configuration changes have occurred between Tomcat 6.x and 7.x with regard to cookies and how they're set up. I've tried the following after extensive research
over the last week.
In web.xml: (this will disable URL rewriting under Tomcat 7.x)
<tracking-mode>COOKIE</tracking-mode> under the default session element
In context.xml: (cookies is true by default but I was explicit as I can't get it working)
cookies=true
sessionCookiePath=/
sessionCookieName=WebServerSID
sessionCookieName=1001
I have 2 entries in context.xml for sessionCookieName because the equivalent commands from Tomcat 6.x look like they've been merged into 1.
See http://tomcat.apache.org/migration-7.html#Tomcat_7.0.x_configuration_file_differences
Extract:
org.apache.catalina.SESSION_COOKIE_NAME system property: This has been removed. An equivalent effect can be obtained by configuring the sessionCookieName attribute for the global context.xml (in CATALINA_BASE/conf/context.xml).
org.apache.catalina.SESSION_PARAMETER_NAME system property: This has been removed. An equivalent effect can be obtained by configuring the sessionCookieName attribute for the global context.xml (in CATALINA_BASE/conf/context.xml).
If this is not right then I simply do not understand the syntax that is required and I cannot find anywhere that will simply spell it out in plain black and white.
Under Tomcat 6.x, I would have used Java Options in the config like:
-Dorg.apache.catalina.SESSION_COOKIE_NAME=WebServerSID
-Dorg.apache.catalina.SESSION_PARAMETER_NAME=1001
The application I'm using does not have any of these values set elsewhere so it's not the application.
All these settings are in context/web/server.xml files at the Catalina base
At the end of the day what I need to see in the response headers under Set-Cookies: (as seen using Fiddler) is:
WebServerSID=1001
NOT
JSESSIONID=as8sd9787ksjds9d8sdjks89s898
thanks in advance
regards
The best you can do purely with configuration is to set the jvmRoute attribute of the Engine which will add the constant value to the end of the session ID. Most load-balancers can handle that. It would look like:
JSESSIONID=as8sd9787ksjds9d8sdjks89s898.route1
If that isn't good enough and you need WebServerSID=1001 you'll have to write a ServletFilter and configure that to add the header on every response.