How to dynamically load values โ€‹โ€‹into a Tomcat Context XML file

Given that the Tomcat Context XML file contains confidential information (often including the credentials needed to connect to the database), how can I dynamically load these values โ€‹โ€‹from a source other than plaintext text.xml?

+4
source share
4 answers

Say you have a tomcat / conf / context.xml file that looks something like this:

<?xml version="1.0" encoding="utf-8"?> <Context> <WatchedResource>WEB-INF/web.xml</WatchedResource> <Resource name="jdbc/MyDB" auth="Container" type="javax.sql.DataSource" removeAbandoned="true" removeAbandonedTimeout="15" maxActive="5" maxIdle="5" maxWait="7000" username="${db.mydb.uid}" password="${db.mydb.pwd}" driverClassName="${db.mydb.driver}" url="${db.mydb.url}${db.mydb.dbName}?autoReconnectForPools=true&amp;characterEncoding=UTF-8" factory="com.mycompany.util.configuration.CustomDataSourceFactory" validationQuery="SELECT '1';" testOnBorrow="true"/> </Context> 

What we want to replace in this case is something in the $ {file. *} in this resource definition. However, with a slight change to the code below, you can perform these substitutions by almost any criteria you would like.

Notice the line factory="com.mycompany.util.configuration.CustomDataSourceFactory"

This means that Tomcat will try to use this factory to process this resource. It should be noted that this means that this factory should be in the Tomcat classpath at startup (Personally, I put mine in the JAR in the Tomcat lib directory).

This is what my factory looks like:

 package com.mycompany.util.configuration; import java.util.Hashtable; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.naming.Context; import javax.naming.Name; import javax.naming.RefAddr; import javax.naming.Reference; import javax.naming.StringRefAddr; import javax.naming.spi.ObjectFactory; import org.apache.commons.dbcp.BasicDataSourceFactory; public class CustomDataSourceFactory extends BasicDataSourceFactory implements ObjectFactory { private static final Pattern _propRefPattern = Pattern.compile("\\$\\{.*?\\}"); //http://tomcat.apache.org/tomcat-6.0-doc/jndi-resources-howto.html#Adding_Custom_Resource_Factories @Override public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception { if (obj instanceof Reference) { Reference ref = (Reference) obj; System.out.println("Resolving context reference values dynamically"); for(int i = 0; i < ref.size(); i++) { RefAddr addr = ref.get(i); String tag = addr.getType(); String value = (String) addr.getContent(); Matcher matcher = _propRefPattern.matcher(value); if (matcher.find()) { String resolvedValue = resolve(value); System.out.println("Resolved " + value + " to " + resolvedValue); ref.remove(i); ref.add(i, new StringRefAddr(tag, resolvedValue)); } } } // Return the customized instance return super.getObjectInstance(obj, name, nameCtx, environment); } private String resolve(String value) { //Given the placeholder, do stuff to figure out what it true value should be, and return that String. //This could be decryption, or maybe using a properties file. } } 

Then, as soon as this code is in the classpath, restart Tomcat and view the catalina.out file for log messages. NOTE. System.out.println operators are more likely to print sensitive information in your logs, so you can delete them after debugging is complete.

In the isolation, I wrote this because I found that many examples are too specific for one particular topic (for example, the use of cryptography), and I wanted to show how this can be done in general. In addition, some other answers to this question do not explain themselves very well, and I had to do something to figure out what needs to be done to complete this work. I wanted to share my findings with you guys. Please feel free to comment on this by asking any questions or making corrections if you find problems, and I will definitely get corrections in my answer.

+7
source

If you want to do this, you can implement your own class that implements very simple

org.apache.tomcat.util.IntrospectionUtils.PropertySource

and register it using the system property

org.apache.tomcat.util.digester.PROPERTY_SOURCE

We did the same in order to use the encrypted values โ€‹โ€‹in context.xml, server.xml, etc.

See http://tomcat.apache.org/tomcat-7.0-doc/config/systemprops.html#Property_replacements

If you implement a zookeeper property source, I am interested in the result, as I plan to do the same.

+6
source

Why survive all the troubles?

Just configure sensitive parameters on the host machine as JVM System Properties , and Tomcat will automatically recognize them and replace the values โ€‹โ€‹for all ${...} placeholders. In this way, sensitive data remains on the host machine and never leaks into the source code.

From: https://tomcat.apache.org/tomcat-7.0-doc/config/

Supported variable substitution Apache Ant-style; a system property called propname can be used in the configuration file using the syntax $ {propname}. All system properties are available, including those installed using the -D syntax automatically created by the JVM and configured in the $ CATALINA_BASE / conf / catalina.properties file.

@Note. This answer assumes that your context.xml and other Tomcat configuration files are under SCM, which usually happens when using virtualized deployments (like Openshift).

+3
source

You can not. The question implies endless regression. If you have a secure source for downloading credentials, you will need to determine the credentials for the secure source, etc. + Ad infinitum. +

Ultimately, the answer to this question is the physical security of the server machine and access control to who can see its deployment directories from the outside.

+1
source

Source: https://habr.com/ru/post/1444182/


All Articles