2010-08-06 79 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 
    } 
}