Jboss 数据源密码明文加密 + 小程序


现在一个客户做审计要求需要把存储在文件中的数据库密码加密,网上也有很多教程了,这里主要是做一个补充,写了一个小程序,批量修改配置,为什么这样做呢?


我们这边的产品在Jboss中配置了多个数据源,数一下:1,2,3...大概有10个吧,可能更多,一个个改费时呀.


这边的Jboss版本为 5.1.0.


下面来看一看.


默认数据源配置如下:

<local-tx-datasource>
	<jndi-name>jdbc/ADMIN</jndi-name>
	<connection-url>jdbc:oracle:thin:@sce10:1521:XXXX</connection-url>
	<driver-class>oracle.jdbc.OracleDriver</driver-class>
	<user-name>XXXX</user-name>
	<password>XXXX</password>
	<min-pool-size>0</min-pool-size>
	<max-pool-size>100</max-pool-size>
	<new-connection-sql>ALTER SESSION SET NLS_DATE_FORMAT = 'yyyy/mm/dd hh24:mi:ss'</new-connection-sql>
</local-tx-datasource>
用户名密码都是明文.


我们可以进行小小的更改,编辑它:

<local-tx-datasource> 
    <jndi-name>jdbc/ADMIN</jndi-name>  
    <connection-url>jdbc:oracle:thin:@sce10:1521:XXXX</connection-url>  
    <driver-class>oracle.jdbc.OracleDriver</driver-class>  
    <min-pool-size>0</min-pool-size>  
    <max-pool-size>100</max-pool-size>  
    <new-connection-sql>ALTER SESSION SET NLS_DATE_FORMAT = 'yyyy/mm/dd hh24:mi:ss'</new-connection-sql>  
    <security-domain>SCPRD_Encrypt_ADMIN_Password</security-domain>
</local-tx-datasource>  
编辑后,变成如上所示,那么这个安全域配置在哪里呢,往下看


编辑 JBOSS_HOME/server/Default/Conf/login-config.xml,添加一个节点:

<application-policy name="SCPRD_Encrypt_SCPRD_WMWHSE1_Password">
	<authentication>
		<login-module code="org.jboss.resource.security.SecureIdentityLoginModule" flag="required">
			<module-option name="username">wmwhse1</module-option>
			<module-option name="password">-7777fac1e4b05d45207a6df87216de44</module-option>
			<module-option name="managedConnectionFactoryName">jboss.jca:service=LocalTxCM,name=jdbc/ADMIN</module-option>
		</login-module>
	</authentication>
</application-policy>
name: DataSource中 security-domain 对应,一定要一致.

username:数据库用户名

password:加密后的密码

managedConnectionFactoryName:name={Datasource 中的JndiName},这点也很重要


其实上面都挺简单的.



下面重点来了,密码加密命令(其实就是加载Jboss的一个jar文件,调用Java类生成输出)

java -cp "C:\Infor\sce\jboss-5.1.0.GA\lib\jboss-logging-spi.jar;C:\Infor\sce\jboss-5.1.0.GA\lib\jboss-jmx.jar;C:\Infor\sce\jboss-5.1.0.GA\lib\jboss-common-core.jar;C:\Infor\sce\jboss-5.1.0.GA\common\lib\jboss-jca.jar;C:\Infor\sce\jboss-5.1.0.GA\common\lib\jbosssx.jar" org.jboss.resource.security.SecureIdentityLoginModule $password$

执行就行了,控制台会输出密码的.


重点又来了,数据源太多,一个个改费劲,上一小段代码.

package org.xml.datasource;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

/**
 * 数据源批量加密
 * @author berr
 * 2014.11.07
 */
public class Convert2Encoded {

	/**
	 * 加载XML
	 * @param path 文件路径
	 * @return 返回Dom4j解析对象
	 */
	public Document load(String path){
		InputStream is = null;
		try {
			is = new FileInputStream(new File(path));
			SAXReader saxr = new SAXReader();
			return  saxr.read(is);
			
		} catch (Exception e) {
			is = null;
			e.printStackTrace();
		}finally{
			try {
				is.close();
			} catch (IOException e) {
				is = null; 
			}
		}
		return null;
	}
	
	/**
	 * 转换
	 * @param document
	 * @throws Exception
	 */
	public void convertTo(Document document) throws Exception{
		
		List<Element> datasources = document.selectNodes("//datasources/local-tx-datasource"); //XPATH 获取数据源节点
		
		for (Element d : datasources) {
			
			String jndiName = d.selectSingleNode("jndi-name").getText();
			
			Node user = d.selectSingleNode("user-name");
			Node pass = d.selectSingleNode("password");
			
			
			String userName = user.getText();
			String password = pass.getText();
			password = encryptPassword(password); //加密密码,此classpath已加入jboss的几个jar文件
			
			//移除用户名密码节点
			d.remove(user); 
			d.remove(pass);
			
			
			d.addElement("security-domain"); //增加安全域节点
			
			String newName = createName(jndiName);
			
			d.selectSingleNode("security-domain").setText(newName);
			
			output(newName,jndiName,userName,password);
			
		}
		
		
		
	}
	
	/**
	 * 输出 login-config.xml 配置信息,需要手工复制添加
	 * @param name
	 * @param jndiName
	 * @param user
	 * @param password
	 */
	public void output(String name,String jndiName,String user,String password){
		StringBuffer tpl = new StringBuffer("<application-policy name=\"%s\">\n");
		tpl.append("\t<authentication>\n");
		tpl.append("\t\t<login-module code=\"org.jboss.resource.security.SecureIdentityLoginModule\" flag=\"required\">\n");
		tpl.append("\t\t\t<module-option name=\"username\">%s</module-option>\n");
		tpl.append("\t\t\t<module-option name=\"password\">%s</module-option>\n");
		tpl.append("\t\t\t<module-option name=\"managedConnectionFactoryName\">jboss.jca:service=LocalTxCM,name=%s</module-option>\n");
		tpl.append("\t\t</login-module>\n");
		tpl.append("\t</authentication>\n");
		tpl.append("</application-policy>");
		System.out.println(String.format(tpl.toString(), name,user,password,jndiName));
	}
	
	
	public void startConvert(String path) throws Exception{
		Document doc = load(path);
		
		convertTo(doc);
		
		System.out.println("---------------------------------------------------------------------------");
		System.out.println("1.The above content append to jboss/conf/login-config.xml ");
		
		String newpath = path + ".new";
		
		System.out.println("---------------------------------------------------------------------------");
		System.out.println("2.The new datasrouce config file ["+newpath+"] replace to jboss/deploy/*.ds.xml ");
		
		writer(newpath,doc);
	}
	
	public String createName(String jndiName){
		
		int i = jndiName.indexOf("/");
		
		String newName = jndiName;

		if(i > -1){
			newName = jndiName.substring(i + 1, jndiName.length());
		}
		
		String tpl = "SCPRD_Encrypt_%s_Password";
		return String.format(tpl, newName);
		
	}
	
	
	/**
	 * 加密密码
	 * @param password
	 * @return
	 * @throws Exception
	 */
	public String encryptPassword(String password) throws Exception{
		
		/**
		 这里大家会觉得很奇怪,为什么要用反射,下面解答一下
		 Jboss这个SecureIdentityLoginModule类是做加密解密的,但是他的加密方法是私有的,我这个包不能访问
		 你可能会问调用main方法也可以呀,回答是NO,main方法是在控制台输出,不是返回一个变量
		 那么问题来了,怎么办? 反射就可很简单的解决了,下面代码就是
		 * */
		
		Class clz = org.jboss.resource.security.SecureIdentityLoginModule.class;
		Method m = clz.getDeclaredMethod("encode", String.class); 
		m.setAccessible(true);
		Object o = m.invoke(null, password);
		
		return String.valueOf(o);
		
		
	}
	
	/**
	 * 写入XML
	 * @param path
	 * @return
	 * @throws DocumentException 
	 */
	public static void writer(String path,Document document) throws DocumentException{

		XMLWriter writer = null;// 声明写XML的对象
		try {
			OutputFormat format = OutputFormat.createPrettyPrint();
			writer = new XMLWriter(new FileWriter(path), format);
	        writer.write(document);
	        writer.close();
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			try {
				writer.close();
			} catch (IOException e) {
				writer = null;
			}
		}
	}
	
	public static void main(String[] args) throws Exception {
		Convert2Encoded c2e = new Convert2Encoded();
		
		c2e.startConvert("D:\\work\\workspace\\RESOURCE\\tools\\source\\scewebserver-ds.xml");
		
		
		
	}
}



到此结束.



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值