Strange behavior when overriding properties for a spring-boot application deployed as a WAR in a Tomcat - spring-boot

I have a spring-boot application which I need to deploy as a WAR in a tomcat.
I also need to define / override some properties so that this application can work in this environment.
I was able to do so by creating a file tomcat/conf/Catalina/localhost/backend.xml with the same name as my WAR file. Here the content:
<?xml version="1.0" encoding="UTF-8"?>
<Context reloadable="true" crossContext="true" override="true" path="/back" docBase="/home/myAppUser/webapps/backend.war">
<Environment name="spring.profiles.active" value="prod" type="java.lang.String" />
<Environment name="application.attachmentBaseDirectory" value="/home/myAppUser/attachments" type="java.lang.String" />
<Environment name="application.redirect-url" value="http://myapp.mycompany.org/frontend" type="java.lang.String" />
</Context>
All environment variables but application.attachmentBaseDirectory work.
The application continue to use the one defined for my development environment on Windows: C:\tmp\attachments…
Yet, if I create a file /home/myAppUser/application.yml or /home/myAppUser/config/application.yml, the value is correctly overridden…
application:
attachmentBaseDirectory: /home/myAppUser/attachments
But if I define all the values inside this file in place of backend.xml, none of them but application.attachmentBaseDirectory work…
So here is my questions:
Why the overriding in tomcat/conf/Catalina/localhost/backend.xml isn't working for this value, but work for others?
How come the WAR is able to find the application.yml when running inside of a tomcat?
Why the application.attachmentBaseDirectory property does work from the application.yml file, but others don't?
Some more information:
Here the content on my ApplicationProperties.java.
#Component
#ConfigurationProperties("application")
public class ApplicationProperties {
/**
* The URL to which we should redirect the user once he is logged in the application.
*/
private String redirectUrl;
/**
* The base directory in which we should put the attachments.
*/
private String attachmentBaseDirectory;
}
This bean is then use in a #Controller for the redirectUrl to redirect to another web page, and in a #Service for the attachmentBaseDirectory to save files.

I finally found why the property application.attachmentBaseDirectory didn't work when set in tomcat/conf/Catalina/localhost/backend.xml:
It is because it was named application.attachmentBaseDirectory (camel case) and not application.attachment-base-directory (kebab case).
Spring-boot allow relaxed binding, but it seems that to be used through tomcat context, the kebab case way is the one to go.
Yet to solve:
How come the WAR is able to find the application.yml in the home directory when running inside tomcat?
I am suspecting that it is because I launch the tomcat from my home directory.
Why the application.attachmentBaseDirectory works from application.yml but others properties don't?

Related

Restrict remote access to folder inside tomcat webapp folder

I have Spring Boot micro-service based application hosted on Tomcat 9. So, I have multiple folders deployed in {{tomcat root dir}}/webapps folder. I want only one folder to be accessible from outside network (gateway service). Others folder should be accessible only from localhost.
So, how can I achieve this without adding context.xml? I know this can be achieved by adding context.xml but context.xml is getting overwritten after every war deployment.
So want to check if this can be achieved at more global level like modifying server.xml.
Valves must be defined in a <Context> section, but adding a META-INF/context.xml to your application is not the only way to define a context.
If you want to restrict most applications to localhost, the easiest way is to modify $CATALINA_BASE/conf/context.xml:
<Context>
...
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1"" />
</Context>
or $CATALINA_BASE/conf/<engine_name>/<host_name>/context.xml.default (usually $CATALINA_BASE/conf/Catalina/localhost/context.xml.default) if you wish the changes to apply only to a single host.
Every web application context will inherit the <Valve>s in the aforementioned files. Since you want to have a web application (let's say /pubApp) without these restrictions you need to create a file $CATALINA_BASE/conf/<engine_name>/<host_name>/pubApp.xml and set the override attribute to true:
<Context override="true">
<!-- Remember to copy all configuration values from `conf/context.xml`
and `conf/<engine_name>/<host_name>/context.xml.default`
that you wish to apply, since they will not be read anymore.
-->
...
</Context>

LegacyCookieProcessor in standalone Tomcat and Spring Boot [duplicate]

My code is working on tomcat 8 version 8.0.33 but on 8.5.4 i get :
An invalid domain [.mydomain] was specified for this cookie.
I have found that Rfc6265CookieProcessor is introduced in tomcat 8 latest versions.
It says on official doc that this can be reverted to LegacyCookieProcessor in context.xml but i don't know how.
Please let me know how to do this.
Thanks
You can try in context.xml
<CookieProcessor className="org.apache.tomcat.util.http.LegacyCookieProcessor" />
reference:
https://tomcat.apache.org/tomcat-8.0-doc/config/cookie-processor.html
Case 1: You are using Standalone Tomcat & have access to change files in tomcat server
Please follow answer by #linzkl
Case 2: You are using Standalone Tomcat but you don't have access to change files in tomcat server
Create a new file called context.xml under src/main/webapp/META-INF folder in your application & paste the content given below
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<WatchedResource>WEB-INF/tomcat-web.xml</WatchedResource>
<WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
<CookieProcessor className="org.apache.tomcat.util.http.LegacyCookieProcessor" />
</Context>
When you deploy your application in Standalone Tomcat, the context.xml file you placed under META-INF folder will override the context.xml file given in tomcat/conf/context.xml
Note: If you are following this solution, you have to do it for every single application because META-INF/context.xml is application specific
Case 3: You are using Embedded Tomcat
Create a new bean for WebServerFactoryCustomizer
#Bean
WebServerFactoryCustomizer<TomcatServletWebServerFactory> cookieProcessorCustomizer() {
return new WebServerFactoryCustomizer<TomcatServletWebServerFactory>() {
#Override
void customize(TomcatServletWebServerFactory tomcatServletWebServerFactory) {
tomcatServletWebServerFactory.addContextCustomizers(new TomcatContextCustomizer() {
#Override
public void customize(Context context) {
context.setCookieProcessor(new LegacyCookieProcessor());
}
});
}
};
}
Enabling the LegacyCookieProcessor which is used in previous versions of Tomcat has solved the problem in my application. As linzkl mentioned this is explained in Apache's website https://tomcat.apache.org/tomcat-8.0-doc/config/cookie-processor.html.
The reason is that the new version of Tomcat does not understand the . (dot) in front of the domain name of the Cookie being used.
Also, make sure to check this post when you are using Internet Explorer. Apparently, it's very likely to break.
You can find context.xml in the following path.
tomcat8/conf/context.xml
<?xml version="1.0" encoding="UTF-8”?>
<!-- The contents of this file will be loaded for each web application —>
<Context>
<!-- Default set of monitored resources. If one of these changes, the -->
<!-- web application will be reloaded. -->
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
<!-- Uncomment this to disable session persistence across Tomcat restarts -->
<!-- <Manager pathname="" /> -->
<CookieProcessor className="org.apache.tomcat.util.http.LegacyCookieProcessor"/>
</Context>
The problem is still with Tomcat9. Same process need to follow for Tomcat 9 to set the class.
Add the class in context.xml file.
If you are using eclipse to run the application, need to set in the context.xml file in the server folder. Refer the below screenshot for more reference.
Hope this helps someone.
SameSite issue in tomcat version < 8.5.47 has resolved
In Tomcat 8.5.47 and bellow (Tomcat 8 versions), setting CookieProcessor tag to enable same site (as given bellow) in context.xml does not work due to a bug in Tomcat.
<CookieProcessor className="org.apache.tomcat.util.http.LegacyCookieProcessor" sameSiteCookies="none" />
If you find in this situation where it is not a easy thing to upgrade tomcat immediately (which I faced recently), or if you find any other case where you just need custom processing in cookies; You can write your own CookieProcessor class to get around.
Please find a custom CookieProcessor implementation and details of it's deployment steps here.
In my case I wrote a custom CookieProcessor based on LegacyCookieProcessor source code that allows tomcat 8.5.47 to enable SameSite attribute in cookies.
As mentioned by #atul, this issue persists in Tomcat 9. It will most likely persist moving forward with all future versions of Tomcat, since this is the new standard.
Using the legacy cookie processor (by adding the line above to the context.xml file) is working well for us. However, the true 'fix' is to adjust how your cookie is formed in the first place. This will need to be done in your application, not in Tomcat.
The new cookie processor does not allow the domain to start with a . (dot). Adjusting your cookie (if possible) to start with a value other than that will fix this problem without reverting to the old, legacy cookie processor.
Also, it should be obvious, but I didn't see it mentioned above: after updating the context.xml file, you need to restart the Tomcat service for the change to take effect.
Cheers!

Create Externalized Configuration in spring-boot along with profiles

I have a spring-boot application with annotations instead of context.xml.
In my src/main/resources folder I have: application-dev.properties and application-test.properties.
which work perfectly for different profiles (while running with VM option like -Dspring.profiles.active=dev)
Now I need to externalize this properties with file in /opt/software/Tomcat8/conf/app.properties
Some props override each other, some don't.
in Tomcat config context.xml I say:
<Environment name="app.properties"
value="file:///opt/software/Tomcat8/conf/app.properties"
type="java.lang.String" override="false"/>
How to use it via JNDI in my application configuring app with no XML but annotations in Spring-bot application class?
I need it to have priority to inner jar properties according to
Link to Spring-boot.doc
One solution I found was to have the vm argument -Dloader.path with the external path when executing the application. Please keep in mind if you're using a fat jar you may need to create the package in Zip model, otherwise it will not work.

Simple axis2.xml for Axis2 embedded in webapp

I am developing a webapp with an embedded webservice with Axis2 using Maven.
The service implementation is a POJO with RPC-style interaction, the target appserver is Tomcat running the Axis2 servlet.
The "Hello world" works but now I need to configure some global axis2 settings in the axis2.xml file (placed under WEB-INF/conf).
Please provide or point to a simple configuration for axis2.xml for this common environment.
The default taken from the binary distribution has too many features activated (hotdeploy?) and also causes this problem:
<soapenv:Reason>
<soapenv:Text xml:lang="en-US">
The ServiceClass object does not implement the required method
in the following form: OMElement ping(OMElement e)
</soapenv:Text>
</soapenv:Reason>
As a reference: http://axis.apache.org/axis2/java/core/docs/servlet-transport.html says to configure the servlet transport in this way, but it does not solve the issue.
<transportReceiver name="http" class="org.apache.axis2.transport.http.AxisServletListener"/>
Apparently the problem is that the default axis2.xml sets raw xml messageReceivers, instead of the RPC ones.
Try to add this to the services.xml for the developed service, should fix the problem.
<messageReceivers>
<messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-only"
class="org.apache.axis2.rpc.receivers.RPCInOnlyMessageReceiver" />
<messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out"
class="org.apache.axis2.rpc.receivers.RPCMessageReceiver" />
</messageReceivers>
"Solution that worked for me was adding the operation tag in the service.xml against the Java Service method name:
<operation name="sayHello" >
<messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out" class="org.apache.axis2.rpc.receivers.RPCMessageReceiver" />
</operation>
<parameter name="ServiceClass" locked="false">com.learning.webservices.pojo.HelloService</parameter>

Spring using JNDI with Tomcat... why do I need a META-INF/context.xml in my project

I am trying to get Spring working with tomcat JNDI resource to access my database. My project works if a META-INF/context.xml in my project with the resource information but once I remove it it stops.. why.
If you deploy a Web application in Tomcat, in the deployment process, Tomcat will copy the META-INF/context.xml file in $CATALINA_HOME/conf/ so the context will be available for your application. Take in mind, that if you remove context.xml from you application because you dont want it, you also have to delete it manually from $CATALINA_HOME/conf/
If you have edited the server.xml for including your dababase resource and is not working when you remove context.xml it could be because you made some mistake defining your resourde in server.xml
UPDATED:
When resource is in server.xml, in context you should make a reference to global resource in server.xml. For example:
<Context crossContext="true" reloadable="true" >
<ResourceLink name="jdbc/myApp" type="javax.sql.DataSource" global="jdbc/myApp" />
</Context>
This is unrelated to Spring.
To use JNDI you are expected to define the various resources either as global configuration or as application specifici configuration. For example JNDI DataSource Configuration
Why do you expect it to work in any other case? How would Tomcat know which resources to provide if you don't define them?
UPDATE:
You define a resouce in your server.xml but you have to associate the resource with your web application. That is why you also need to modify context.xml

Resources