2010-08-06 198 views
14

目前我将密码[未加密]保存在属性文件中。这个密码被放置在使用ant的配置xml中。
[配置xml是数据源,它创建了dbcp.BasicDataSource的对象]如何在apache BasicDataSource中使用加密密码?

现在,是否有可能在蚂蚁目标之后以加密形式复制密码。听说Jasypt可以做到这一点!直到现在我还没有尝试过。但是,问题并没有在这里结束。 BasicDataSource不接受加密的密码。是否有任何替代BasicDatasource。

仅供参考:如果有问题,我正在使用Spring。

回答

2

通过延长现有任务Copy(负责文件复制)创建一个新的任务。通过扩展FilterSet(负责过滤令牌)创建新类型。
看到这里的代码: - How to create nested element for ant task?

的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

property1=value1 
property2=value2 
PASSWORD=^&YUII%%&*(
USERNAME=rjuyal 
CONNECTION_URL=... 
someotherproperty=value 

配置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>@[email protected]</value> 
     </property> 
     <property name="username"> 
      <value>@[email protected]</value> 
     </property> 
     <property name="password"> 
      <value>@[email protected]</value> 
     </property> 
     <property name="poolPreparedStatements"> 
      <value>true</value> 
     </property> 
     <property name="maxActive"> 
      <value>10</value> 
     </property> 
     <property name="maxIdle"> 
      <value>10</value> 
     </property>  
    </bean> 
... 
... 
... 

在执行目标之后,将xml与属性文件中的值一起复制。密码将被加密。

这将处理加密的密码。 EncryptionAwareDataSource

public class EncryptionAwareDataSource extends BasicDataSource{ 
    @Override 
    public synchronized void setPassword(String password) {  
     super.setPassword(Encryptor.getDecryptedValue(password)); 
    } 
} 

这一切;)

3

以下jasypt链接介绍了如何包含加密内容的属性文件可以从您的应用程序中阅读:

http://www.jasypt.org/encrypting-configuration.html

要创建的属性文件从内部ANT我的建议是使用常规任务,如下:

<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> 
2

扩展BasicDataSource,覆盖setPassword和setUserName方法。解密这些方法中的值并将它们传递给超类方法。

16

有了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> 

当您指定的PropertiesPersister在属性占位符的子类,弹簧负荷的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 
     ... 
    } 
    ... 
} 

希望它有帮助。

编辑 如果您使用Jasypt,则无需定义任何PropertiesPersister。从Jasypt documentation

Jasypt提供这些配置相关的Spring类可以读取的.properties使用加密值的文件的实现(如由EncryptableProperties类管理的那些)和透明地处理他们的Spring的其它部分应用程序bean。

有了这个,你可以定义jdbc.properties这样

jdbc.driver=com.mysql.jdbc.Driver 
jdbc.url=jdbc:mysql://localhost/reportsdb 
jdbc.username=reportsUser 
jdbc.password=ENC(G6N718UuyPE5bHyWKyuLQSm02auQPUtm) 

和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> 

这样,你就可以把密码解密隐藏属性在启动应用程序时将其放入环境变量中,稍后取消设置。

+2

非常有帮助。只是一个微不足道的更正,在属性文件中它是jdbc.driver,但在bean定义中它是$ {jdbc.driverClassName}。 – jbird 2013-08-30 17:35:09

3

BasicDataSource的情况下不完全正确。

如果您读取了BasicDataSource的javadoc,则在初始化池后setPassword()不起作用。在第一次调用以下方法之一时初始化池:getConnectionsetLogwriter,setLoginTimeout,getLoginTimeout,getLogWriter

编号:http://www.docjar.com/html/api/org/apache/commons/dbcp/BasicDataSource.java.html

所有这些方法调用createDataSource()最后。

因此新的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 
    } 
}