2010-08-06 43 views
14

Hiện tại tôi đang giữ mật khẩu [không được mã hóa] trong tệp thuộc tính. Mật khẩu này được đặt như trong cấu hình xml sử dụng ant.
[Cấu hình xml là dành cho nguồn dữ liệu, nó đang tạo đối tượng của dbcp.BasicDataSource]Làm thế nào để sử dụng mật khẩu được mã hóa trong apache BasicDataSource?

Bây giờ, có thể sau khi mục tiêu ant mật khẩu được sao chép dưới dạng mã hóa. Nghe nói Jasypt có thể làm điều đó! Cho đến bây giờ tôi đã không cố gắng này. Nhưng, vấn đề không kết thúc ở đây. BasicDataSource không chấp nhận mật khẩu được mã hóa. Có bất kỳ sự thay thế nào cho BasicDatasource không.

FYI: Tôi đang sử dụng Spring, nếu điều đó quan trọng.

Trả lời

2

Tạo một nhiệm vụ mới bằng cách mở rộng nhiệm vụ hiện Copy (chịu trách nhiệm về tập tin bản sao). Tạo một loại mới bằng cách mở rộng FilterSet (chịu trách nhiệm lọc các mã thông báo).
xem mã ở đây: - 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 

cấu hình 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> 
... 
... 
... 

Sau khi thực hiện mục tiêu, xml được sao chép với các giá trị từ tệp thuộc tính. Mật khẩu sẽ được mã hóa.

Thao tác này sẽ xử lý mật khẩu được mã hóa. EncryptionAwareDataSource

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

Đó là tất cả;)

3

Liên kết jasypt sau đây giải thích làm thế nào một tập tin thuộc tính chứa nội dung được mã hóa có thể được đọc từ bên trong ứng dụng của bạn:

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

Để tạo tập tin thuộc tính từ bên trong ANT đề nghị của tôi là sử dụng các nhiệm vụ hấp dẫn như sau:

<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

Mở rộng phương thức BasicDataSource, ghi đèPassword và setUserName. Giải mã các giá trị trong các phương thức đó và chuyển chúng vào các phương thức siêu lớp.

16

Với mùa xuân có cách tốt hơn: sử dụng lớp 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> 

Khi bạn chỉ định một lớp con của PropertiesPersister trong placeholder tài sản, mùa xuân nạp jdbc.properties và giải mã các tập tin sử dụng lớp đó. Có thể một cái gì đó như:

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 
     ... 
    } 
    ... 
} 

Hy vọng điều đó sẽ hữu ích.

EDIT Nếu bạn sử dụng Jasypt, bạn không cần phải xác định bất kỳ PropertiesPersister. Từ Jasypt documentation:

Jasypt cung cấp một thực hiện của các lớp này mùa xuân cấu hình liên quan đến có khả năng đọc .properties file với các giá trị được mã hóa (giống như những người bởi lớp EncryptableProperties quản lý) và xử lý chúng một cách minh bạch để phần còn lại của mùa xuân đậu ứng dụng.

Với điều này, bạn có thể xác định jdbc.properties như thế này

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

và cấu hình mùa xuân có thể như thế này

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

Bằng cách này, bạn có thể đặt mật khẩu cho giải mã thuộc tính ẩn trong một biến môi trường khi bạn khởi động ứng dụng và hủy bỏ nó sau này.

+2

Rất hữu ích. Chỉ cần chỉnh sửa tầm thường, trong tệp thuộc tính, nó là jdbc.driver nhưng trong định nghĩa bean thì nó là $ {jdbc.driverClassName}. – jbird

3

Không hoàn toàn đúng trong trường hợp BasicDataSource.

Nếu bạn đọc javadocs cho BasicDataSource, setPassword() không có hiệu lực khi hồ bơi đã được khởi tạo.Hồ bơi được khởi tạo lần đầu tiên khi một trong các phương pháp sau được gọi: getConnection, setLogwriter, setLoginTimeout, getLoginTimeout, getLogWriter.

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

Tất cả những phương pháp gọi createDataSource() cuối cùng.

Vì vậy, lớp BasicDataSource mới của bạn chỉ cần ghi đè phương pháp createDataSource() Something như thế này:

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 
    } 
} 
Các vấn đề liên quan