2010-08-06 13 views
14

Attualmente sto mantenendo la password [non crittografata] in un file di proprietà. Questa password viene inserita come è nella configurazione xml usando formica.
[L'XML di configurazione è per origine dati, si sta creando l'oggetto del dbcp.BasicDataSource]Come utilizzare la password crittografata in Apache BasicDataSource?

Ora, è possibile che dopo il target formica la password viene copiato in forma criptata. Ho sentito che il Jasypt può farlo! Fino ad ora non ho provato questo. Ma il problema non finisce qui. BasicDataSource non accetta password crittografata. C'è qualche sostituzione per BasicDatasource.

FYI: Sto usando Spring, se questo è importante.

risposta

2

creare una nuova attività, estendendo un'attività esistente Copy (responsabile per la copia dei file). Crea un nuovo tipo estendendo FilterSet (responsabile del filtraggio dei token).
vedere il codice qui: - 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 

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

Dopo l'esecuzione della destinazione, il xml viene copiato con i valori dal file delle proprietà. La password sarà crittografata.

Questo gestirà la password crittografata. EncryptionAwareDataSource

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

E' tutto;)

3

Il seguente link jasypt spiegato come un file di proprietà che contiene il contenuto cifrato può essere letto dall'interno dell'applicazione:

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

Per creare il file delle proprietà da dentro ANT il mio suggerimento è quello di utilizzare l'attività groove come segue:

<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

Estendere BasicDataSource, override setPassword e metodi setUserName. Decrittografare i valori in questi metodi e passarli a metodi di super classe.

16

Con Spring esiste un modo migliore: utilizzare la classe 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> 

Quando si specifica una sottoclasse di PropertiesPersister nel segnaposto proprietà, Primavera caricare il jdbc.properties e decodificare il file con quella classe. Forse qualcosa del tipo:

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

Spero che aiuti.

EDIT Se si utilizza Jasypt, non è necessario definire qualsiasi PropertiesPersister. Dal Jasypt documentation:

Jasypt fornisce un'implementazione di queste classi primavera legati alla configurazione in grado di leggere i file con valori crittografati .properties (come quelle gestite dalla classe EncryptableProperties) e gestirli in modo trasparente per il resto della primavera fagioli di applicazione.

Con questo, è possibile definire jdbc.properties come questo

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

e la configurazione di primavera potrebbe essere simile a questo

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

In questo modo, si può mettere la password per decriptare la proprietà nascosta in una variabile di ambiente quando si avvia l'applicazione e la si disattiva in un secondo momento.

+2

molto utile. Solo una correzione banale, nel file delle proprietà è jdbc.driver ma nella definizione del bean è $ {jdbc.driverClassName}. – jbird

3

Non completamente vero nel caso di BasicDataSource.

Se si leggono le javadoc per BasicDataSource, setPassword() non ha alcun effetto una volta che il pool è stato inizializzato.Il pool viene inizializzato la prima volta in cui viene invocato uno dei seguenti metodi: getConnection, setLogwriter, setLoginTimeout, getLoginTimeout, getLogWriter.

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

Tutti questi metodi chiamano createDataSource() alla fine.

Quindi la tua nuova classe BasicDataSource ha solo bisogno di eseguire l'override del metodo createDataSource() Qualcosa di simile a questo:

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 
    } 
} 
Problemi correlati