如何将值动态加载到 Tomcat 的 Context XML 文件中 [英] How to dynamically load values into Tomcat's Context XML file

查看:51
本文介绍了如何将值动态加载到 Tomcat 的 Context XML 文件中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

鉴于 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&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 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 文件中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆