I am trying to understand the Spring posted description of the problem and resolution alternatives
https://spring.io/blog/2022/03/31/spring-framework-rce-early-announcement
However, I do not understand why this would be Tomcat specific. Wouldnt the same issue exist for war files deployed to Jetty or Wildfly?
This particular exploit demostration is based on the custom custom implementation of one of tomcat specific classloaders having referrence to the servlet environment context. This is why this demo is tomcat specific especially that is exploits the fact that one of the logger valves is the first one in the processing pipeline (this is used to write custom jsp code as a log file in webapps root)
Also it requires Java9+ as it uses access trough class.getModule() which is not present in earlier versions
Related
I'm trying to set a custom log Handler in my Spring Boot (version 2.6.3) application. The result is a ClassNotFound as described in this other question
Can't override java.util.logging.LogManager in a Spring Boot web application: Getting java.lang.ClassNotFoundException on already loaded class
Based on the answer to that question, it seems I need my Handler and all its dependencies to be placed into the root of the executable jar.
Is there a direct way to accomplish this during the Maven build, i.e. not by extracting and repackaging the jar myself post-build?
This issue is a result of BOOT-INF fat jar structure introduced by Spring Boot 1.4.
There is currently no straightforward solution, and it appears some of the Spring Boot maintainers do not agree there is a problem, so it could be a long time before the situation changes:
Issue #6626: Make it easier to package certain content in the root of a fat jar
Issue #12659: Starting executable war with -Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager produces a ClassNotFoundException
WORKAROUND #1
I had to do two things to get my application working again with a custom log handler. 1) use Maven Shade to package up the log handler with all its dependencies, and 2) launch the app with using the PropertiesLauncher class in the command line instead of using java -jar:
java -cp executable.jar:logger-shaded.jar -Dloader.main=mypackage.myapp org.springframework.boot.loader.PropertiesLauncher
The executable.jar, logger-shaded.jar, and mypackage.myapp are placeholders specific to my project, so adjust accordingly.
WORKAROUND #2
If the handler is loaded from code in a config class or from main() instead of being specified in the file loaded via java.util.logging.config.file, as discussed in the comments to the answer in this other question, then everything works as expected. I actually prefer this over Workaround #1 as it results in a smaller deployment, but it does require writing a few more lines of code.
Could be a silly question, but...
I have a Spring-based WAR application that runs 80% of the installations on Tomcat and the rest 20% on WebSphere.
I need to simply get the path of the folder where Spring's MultipartFilter (using Commons multipart resolver) stores files being uploaded. I have never set it manually, and it actually belongs to the Catalina work directory as I found out in my Tomcat installations.
For the moment, I just need to get that path. I have control of my application so no one is going to change it without notice.
I would like to know if there is a server-agnostic way to know where my Spring-based application is going to store Multipart files.
E.g. from this question I can see I can use catalina.base, but in Tomcat... not in JBoss or WebSphere. It could cost me a couple of if/else statements...
Spring tries to do it already when no default value is set
WebUtils.getTempDir(servletContext)
Which simply does:
return ((File)servletContext.getAttribute("javax.servlet.context.tempdir"));
So simply if no one overrides that location in the filter properties (and that is my case) I can rely on the default.
More in general, one may have to inspect the instance of DiskItemFileFactory to get the path to the repository
I'm afraid this question might not be as "close ended" as a StackOverflow question should be. Hopefully, I'm wrong.
Context
We have a project (the typical Java EE with a JSF web GUI) that, due to requirement's specificities, we needed to split in two projets. One of these new split projects is a subset of the previous, with some slight differences.
So, from ORIGINAL_JAVAEE_WEBAPP.war we created: ORIGINAL_JAVAEE_WEBAPP-Proj01.war and ORIGINAL_JAVAEE_WEBAPP-Proj02.war.
In order to avoid redundancy we've decide to create a JAR file with all the facelets, managed beans and related pojos. The idea was that each WAR would include this JAR, use whatever they need and, then, the WAR would have the specific pages, logos, ...
The problem
I've created a simple example just to practice having a JAR file with facelets and having two WAR files including and using these facelets. In this example, things worked flawlessly.
Nevertheless, "the real world" is not that simple. Our project also relies on Primefaces, Spring Core and Spring Security, just to mention a few.
The implementation is not yet finished - far from it. Right now, under the same Maven project, I've created the JAR module, moved the beans and the facelets to that module and included it as a dependency in the WAR file module.
The problem is that, now, my "FacesContext.getViewRoot().getViewId()" tells me that viewId is "someName.jsp" and not "someName.jsf". This simple change messes up with our "legacy" "authentication phase listener" (a phase listener to ensure that a user is logged in and redirect accordingly) implementation.
So, what can be happening here? Do any of you have any hint of what my next steps might be in order to track the root source of this problem?
Thanks and regards.
This could be an issue with the JSF ViewHandlers registered for the FacesContext. What version of JSF are you using and are there any view handlers defined in the JSF context xml.
Also please check in the web.xml the context params :javax.faces.DEFAULT_SUFFIX, javax.faces.FACELETS_VIEW_MAPPING
I'm working on a project that uses two maven projects (named core and webapp); core is built with JAR packaging and used for two different purposes: as a stand-alone app (essentially an executable JAR), and also embedded into webapp.
For its purpose as a stand-alone app, core needs to have its own logback configuration (a logback.xml file) that needs to be included on the classpath. Normal Maven convention would have me put it in src/main/resources/logback.xml. That works fine, but causes a problem when the core JAR is included in webapp. webapp needs to have its own logback configuration, but the container (tc Server or Jetty) is picking up the one from core.jar first.
I realize that logback can be told about a custom config location via a system property (-D on the command line) but that's not viable in a app container like Tomcat or Jetty.
I've read some other people asking about this situation, but none of the solutions I've seen sits well with me. One solution involved setting up a context listener that runs early in the webapp initialization and explicitly configures logback based on a <context-param>. That's a bit brutish in my opinion, and probably a hard sell to my fellow dev team when log4j "just works" in this situation.
I'm far from a Maven expert, so I'm hoping there is some elegant way to get Maven to help me here. Or perhaps some logback extension or add-on that makes it more web-app friendly. Or even a clever idea that I haven't thought of.
There are a number of possible solutions, but the easiest is to put the file in its own module and mark the dependency as provided. The, conspire to have it on the classpath when running the standalone version of the app.
The solution that we ended up using was to leave only the common "non-app" pieces (code and configuration) in core and then extract the other "app" pieces into a new module (batch-app).
The logging configuration only lives in the 2 app projects (webapp and batch-app) that depend on core. core has a logback-test.xml configuration in it, but that's excluded from the JAR that maven builds (since it's in the src/test/resources folder).
We are using cucumber-jvm to write an integration test layer in our application. One of the challenges we are finding is managing the database between the tests and the web application.
A typical scenario is that we want to persist some entities in a Given step of a scenario, then perform some actions on the user interface that may, in turn, persoist more entities. At the end, we want to clean the database. Because the cucumber-jvm tests are in one jvm and the web application is running in another jvm we cannot share a transaction (at least in a way of which I am aware) so the database must be cleaned manually.
My initial thought was to use an Embedded Tomcat server running off of an embedded in-memory database (HSQLDB) in the same JVM as the cucumber-jvm test. This way we might be able to share a single spring container, and by extension a single transaction, from which all objects could be retrieved.
During my initial tests it looks like Spring gets loaded and configured twice: once when the test starts and the cucumber.xml is read, and a second time when the embedded tomcat starts and the web application reads its applicationContext.xml. These appear to be in two completely separate containers because if I try to resolve an object in one container that is specified in the other container then it doesn't resolve. If I duplicate my configuration then I get errors about duplicate beans with the same id.
Is there a way that I can tell Spring to use the same container for both my test application and the embedded tomcat?
I'm using Spring 3.2.2.GA and Embedded Tomcat 7.0.39 (latest versions of both libraries).
Am I crazy? Do I need to provide more technical details? Apologies if I use some incorrect terminology.
Thanks
p.s. If my problem seems familiar to you and you can suggest an alternative solution to the one I am trying, please let me know!
Jeff,
It is normal that spring is loaded twice. There are two places where two spring contexts are created:
In the servlet container listener org.springframework.web.context.ContextLoaderListener that is configured in web.xml. This one reads its configuration from the file set by the context-param contextConfigLocation.
In the implementation of ObjectFactory provided by cucumber-spring plugin cucumber.runtime.java.spring.SpringFactory. This one reads its configuration from cucumber.xml.
The two spring contexts are totally different and their instances are kept in two different places. As a servlet context attribute for the former and kept by the JavaBackend for the latter.
When starting the embedded tomcat, it is possible to get access to the servlet context and thus set ourself the spring context used bt tomcat with the one from cucumber. But, spring has a special class called WebApplicationContext for context used in a servlet container. The cucumber SpringFactory on other hand creates its context through ClassPathXmlApplicationContext. So unless there is a way to specify the type of application context from the xml config, we will have to provide an ObjectFactory that shoots a WebApplicationContext.
What we can do is to have two web.xml. One for the normal and one for the test. For the test, we use our version of the ContexLoader listener.