原文:https://blog.youkuaiyun.com/iberr/article/details/40896479
现在一个客户做审计要求需要把存储在文件中的数据库密码加密,网上也有很多教程了,这里主要是做一个补充,写了一个小程序,批量修改配置,为什么这样做呢?
我们这边的产品在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");
-
}
-
}
到此结束.