问题描述
鉴于Tomcat的Context XML文件倾向于包含敏感信息(通常包括连接到数据库所需的凭据),我该如何从纯文本context.xml以外的源动态加载这些值?
Given that Tomcat's Context XML file tends to contain sensitive information (often including credentials needed to connect to a Database), how can I dynamically load these values from a source other than the plain-text context.xml?
推荐答案
假设您有一个看起来像这样的tomcat/conf/context.xml文件:
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&characterEncoding=UTF-8"
factory="com.mycompany.util.configuration.CustomDataSourceFactory"
validationQuery="SELECT '1';"
testOnBorrow="true"/>
</Context>
在这种情况下,我们要替换的是此资源定义中$ {.*}中的任何内容.但是,只要对下面的代码稍加修改,就可以在几乎任何条件下执行这些替换.
What we want to replace in this case is anything in the ${.*} stuff in this resource definition. With slight modification to the code below, however, you can perform these substitutions on pretty much whatever criteria you'd like.
注意行factory="com.mycompany.util.configuration.CustomDataSourceFactory"
这意味着Tomcat将尝试使用该工厂来处理此资源.应该提到的是,这意味着该工厂在启动时必须位于Tomcat的类路径上(就我个人而言,我将其放在Tomcat lib
目录中的JAR中).
What this means is that Tomcat will attempt to use this factory to process this resource. It should be mentioned that this means that this factory will have to be on Tomcat's classpath on startup (Personally, I put mine in a JAR in the Tomcat lib
directory).
这是我工厂的样子:
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's true value should be, and return that String.
//This could be decryption, or maybe using a properties file.
}
}
然后,一旦此代码在类路径中,请重新启动Tomcat并观察catalina.out的日志消息.注意:System.out.println
语句可能最终将敏感信息打印到您的日志中,因此您可能希望在调试完成后将其删除.
Then, once this code is on the classpath, restart Tomcat and watch catalina.out for the log messages. NOTE: The System.out.println
statements will likely end up printing sensitive information to your logs, so you may want to remove them once you are done debugging.
在一个旁注中,我之所以写出来,是因为我发现许多示例对于某个特定主题而言太具体了(例如,利用密码学),并且我想展示如何通用地做到这一点.此外,这个问题的其他一些答案并不能很好地解释自己,因此我不得不做一些挖掘工作,以弄清楚完成这项工作需要做些什么.我想与大家分享我的发现.请随时对此发表评论,提出任何问题,或者在发现问题时进行更正,我们将确保将这些修复程序汇总到我的答案中.
On a sidenote, I wrote this out because I found that many examples were too specific to one specific topic (such as utilizing cryptography), and I wanted to show how this can be done generically. Furthermore, some of the other answers to this question don't explain themselves very well, and I had to do some digging to figure out what needed to be done to make this work. I wanted to share my findings with you guys. Please feel free to comment on this, asking any questions, or making corrections if you find problems, and I'll be sure to roll the fixes into my answer.
这篇关于如何将值动态加载到Tomcat的Context XML文件中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!