Java 如何在 apache BasicDataSource 中使用加密密码?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3423135/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to use encrypted password in apache BasicDataSource?
提问by Rakesh Juyal
At present i am keeping the password [ unencrypted ] in a property file. This password get placed as is in the configuration xml using ant.
[ The configuration xml is for datasource, it is creating the object of dbcp.BasicDataSource ]
目前,我将密码 [未加密] 保存在一个属性文件中。使用 ant 将此密码按原样放置在配置 xml 中。
[配置xml用于数据源,它正在创建dbcp.BasicDataSource对象]
Now, is it possible that after the ant target the password is copied in encrypted form. Heard the Jasypt can do that! Till now i haven't tried this. But, the problem doesn't end here. BasicDataSource do not accept encrypted password. Is there any replacement for BasicDatasource.
现在,是否有可能在蚂蚁目标之后以加密形式复制密码。听说 Jasypt 可以做到这一点!直到现在我还没有尝试过这个。但是,问题还不止于此。BasicDataSource 不接受加密密码。BasicDatasource 有什么替代品吗?
FYI: I am using Spring, if that matters.
仅供参考:如果这很重要,我正在使用 Spring。
采纳答案by Rakesh Juyal
Create a new task by extending existing task Copy
( responsible for file-copy ). Create a new type by extending FilterSet
( responsible for filtering of tokens ).
see the code here:-
How to create nested element for ant task?
通过扩展现有任务Copy
(负责文件复制)来创建一个新任务。通过扩展创建一个新类型FilterSet
(负责过滤令牌)。
请参阅此处的代码:-
如何为 ant 任务创建嵌套元素?
build.xml
构建文件
<target name="encrypted-copy" >
<CopyEncrypted todir="dist/xyz/config" overwrite="true">
<fileset dir="config"/>
<encryptionAwareFilterSet>
<filtersfile file="conf/properties/blah-blah.properties" />
</encryptionAwareFilterSet>
</CopyEncrypted>
</target>
blah-blah.properties
blah-blah.properties
property1=value1
property2=value2
PASSWORD=^&YUII%%&*(
USERNAME=rjuyal
CONNECTION_URL=...
someotherproperty=value
configuration xml
配置文件
<bean id="dataSource"
class="com.xyz.datasource.EncryptionAwareDataSource"
destroy-method="close" autowire="byName">
<property name="driverClassName">
<value>com.ibm.db2.jcc.DB2Driver</value>
</property>
<property name="url">
<value>@CONNECTION_URL@</value>
</property>
<property name="username">
<value>@USERNAME@</value>
</property>
<property name="password">
<value>@PASSWORD@</value>
</property>
<property name="poolPreparedStatements">
<value>true</value>
</property>
<property name="maxActive">
<value>10</value>
</property>
<property name="maxIdle">
<value>10</value>
</property>
</bean>
...
...
...
After the execution of the target the xml is copied with values from properties file. Password will be encrypted.
执行目标后,将使用属性文件中的值复制 xml。密码将被加密。
This will handle the encrypted password. EncryptionAwareDataSource
这将处理加密的密码。 加密感知数据源
public class EncryptionAwareDataSource extends BasicDataSource{
@Override
public synchronized void setPassword(String password) {
super.setPassword(Encryptor.getDecryptedValue( password ));
}
}
That' all ;)
就这些 ;)
回答by Mark O'Connor
The following jasypt link explains how a properties file containing encrypted content can be read from within your application:
以下 jasypt 链接解释了如何从您的应用程序中读取包含加密内容的属性文件:
http://www.jasypt.org/encrypting-configuration.html
http://www.jasypt.org/encrypting-configuration.html
To create the properties file from within ANT my suggestion is to use the groovy task as follows:
要从 ANT 中创建属性文件,我的建议是使用 groovy 任务,如下所示:
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy"/>
<groovy>
import org.jasypt.encryption.pbe.StandardPBEStringEncryptor
def encryptor = new StandardPBEStringEncryptor();
encryptor.setPassword("secret");
def f = new File("config.properties")
f.println "datasource.driver=com.mysql.jdbc.Driver"
f.println "datasource.url=jdbc:mysql://localhost/reportsdb"
f.println "datasource.username=reportsUser"
f.println "datasource.password=ENC("+encryptor.encrypt("dbpassword")+")"
</groovy>
回答by Adisesha
Extend BasicDataSource, override setPassword and setUserName methods. Decrypt the values in those methods and pass them to super class methods.
扩展 BasicDataSource,覆盖 setPassword 和 setUserName 方法。解密这些方法中的值并将它们传递给超类方法。
回答by Ither
With Spring there is a better way: use the PropertyPlaceholderConfigurerclass.
Spring 有一个更好的方法:使用PropertyPlaceholderConfigurer类。
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<value>classpath:com/foo/jdbc.properties</value>
</property>
<property name="propertiesPersister">
<bean class="com.mycompany.MyPropertyPersister" />
</property>
</bean>
<bean id="dataSource" destroy-method="close"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
When you specify a subclass of PropertiesPersisterin the property placeholder, Spring load the jdbc.properties
and decrypt the file using that class. Maybe something like:
当您在属性占位符中指定PropertiesPersister的子类时,Spring 会jdbc.properties
使用该类加载和解密文件。也许是这样的:
public class MyPropertyPersister extends DefaultPropertiesPersister
{
// ... initializing stuff...
public void load(Properties props, InputStream is) throws IOException
{
Cipher decrypter = getCipher();
InputStream cis = new CipherInputStream(is, decrypter);
super.load(props, cis);
}
public void load(Properties props, Reader reader) throws IOException
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
IOUtils.copy(reader, baos);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
Cipher decrypter = getCipher();
InputStream cis = new CipherInputStream(bais, decrypter);
InputStreamReader realReader = new InputStreamReader(cis);
super.load(props, realReader);
}
public void loadFromXml(Properties props, InputStream is) throws IOException
{
Cipher decrypter = getCipher();
InputStream cis = new CipherInputStream(is, decrypter);
super.loadFromXml(props, cis);
}
private Cipher getCipher()
{
// return a Cipher to read the encrypted properties file
...
}
...
}
Hope it helps.
希望能帮助到你。
EDITIf you use Jasypt, you do not need to define any PropertiesPersister
. From the Jasypt documentation:
编辑如果您使用 Jasypt,则不需要定义任何PropertiesPersister
. 从Jasypt 文档:
Jasypt provides an implementation of these configuration-related Spring classes which can read .properties files with encrypted values (like the ones managed by the EncryptableProperties class) and handle them transparently to the rest of the Spring application beans.
Jasypt 提供了这些与配置相关的 Spring 类的实现,它可以读取具有加密值的 .properties 文件(如 EncryptableProperties 类管理的那些),并对其余 Spring 应用程序 bean 透明地处理它们。
With this, you can define jdbc.properties
like this
有了这个,你可以定义jdbc.properties
这样的
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost/reportsdb
jdbc.username=reportsUser
jdbc.password=ENC(G6N718UuyPE5bHyWKyuLQSm02auQPUtm)
and the Spring config may be like this
和 Spring 配置可能是这样的
<bean class="org.jasypt.spring.properties.EncryptablePropertyPlaceholderConfigurer">
<constructor-arg>
<bean class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor">
<property name="config">
<bean class="org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig">
<property name="algorithm" value="PBEWithMD5AndDES" />
<property name="passwordEnvName" value="APP_ENCRYPTION_PASSWORD" />
</bean>
</property>
</bean>
</constructor-arg>
<property name="locations">
<list>
<value>/WEB-INF/classes/jdbc.properties</value>
</list>
</property>
</bean>
<bean id="dataSource" destroy-method="close"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
This way, you can put the password for decrypt the hidden property in an environment variable when you start the application and unset it later.
这样,您可以在启动应用程序时将用于解密隐藏属性的密码放在环境变量中,稍后再取消设置。
回答by huydang
Not entirely true in the case of BasicDataSource
.
在 的情况下不完全正确BasicDataSource
。
If you read the javadocs for BasicDataSource
, setPassword()
has no effect once the pool has been initialized. The pool is initialized the first time one of the following methods is invoked: getConnection
, setLogwriter
, setLoginTimeout
, getLoginTimeout
, getLogWriter
.
如果您阅读了 的 javadocs BasicDataSource
,setPassword()
一旦池被初始化就没有任何影响。池在第一次调用以下方法之一时初始化:getConnection
, setLogwriter
, setLoginTimeout
, getLoginTimeout
, getLogWriter
。
Ref: http://www.docjar.com/html/api/org/apache/commons/dbcp/BasicDataSource.java.html
参考:http: //www.docjar.com/html/api/org/apache/commons/dbcp/BasicDataSource.java.html
All these methods call createDataSource()
eventually.
所有这些方法createDataSource()
最终都会调用。
So your new BasicDataSource class only needs to override the method createDataSource()
Something like this:
所以你的新 BasicDataSource 类只需要覆盖方法createDataSource()
是这样的:
public class NewBasicDataSource extends BasicDataSource {
protected synchronized DataSource createDataSource() throws SQLException {
String decryptedPassword = decryptPassword( super.getPassword() );
super.setPassword( decryptedPassword );
return super.createDataSource();
}
private String decryptPassword( String password ) {
return //logic to decrypt current password
}
}