2010-08-06 9 views
14

Actualmente estoy guardando la contraseña [no encriptada] en un archivo de propiedades. Esta contraseña se coloca como está en la configuración xml usando hormiga.
[El xml configuración es para fuente de datos, está creando el objeto de dbcp.BasicDataSource]Cómo usar la contraseña cifrada en apache BasicDataSource?

Ahora, es posible que después de la tarea ant la contraseña se copia en forma cifrada. ¡Oí que el Jasypt puede hacer eso! Hasta ahora no he probado esto. Pero, el problema no termina aquí. BasicDataSource no acepta contraseña encriptada. ¿Hay algún reemplazo para BasicDatasource.

FYI: Estoy usando Spring, si eso es importante.

Respuesta

2

crear una nueva tarea mediante la extensión de tarea existente Copy (responsable de la copia de archivos). Cree un nuevo tipo ampliando FilterSet (responsable del filtrado de tokens).
ver el código aquí: - 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 

configuración 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> 
... 
... 
... 

Después de la ejecución del objetivo, el xml se copia con los valores del archivo de propiedades. La contraseña será encriptada.

Esto manejará la contraseña cifrada. EncryptionAwareDataSource

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

Eso es todo;)

3

El siguiente enlace Jasypt explica cómo un archivo de propiedades que contiene el contenido cifrado se puede leer desde su aplicación:

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

Para crear el archivo de propiedades desde dentro ANT mi sugerencia es utilizar la tarea maravilloso como sigue:

<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

Extienda BasicDataSource, anule los métodos setPassword y setUserName. Descifra los valores en esos métodos y pásalos a los métodos de superclase.

16

Con Spring hay una manera mejor: use la clase 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> 

Cuando se especifica una subclase de PropertiesPersister en el marcador de posición de la propiedad, el muelle de carga jdbc.properties y descifrar el archivo con esa clase. Tal vez algo así como:

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

Espero que ayude.

EDITAR Si utiliza Jasypt, no es necesario definir cualquier PropertiesPersister. Desde el Jasypt documentation:

Jasypt proporciona una implementación de estas clases de primavera relacionados con la configuración que puede leer los archivos .properties con valores cifrados (como los gestionados por la clase EncryptableProperties) y manejarlos de forma transparente para el resto de la primavera frijoles de aplicación.

Con esto, se puede definir jdbc.properties como esto

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

y la configuración de la primavera puede ser así

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

De esta manera, se puede poner la contraseña para desencriptar la propiedad oculta en una variable de entorno cuando inicia la aplicación y la desarma más tarde.

+2

muy útil. Solo una corrección trivial, en el archivo de propiedades es jdbc.driver pero en la definición de bean es $ {jdbc.driverClassName}. – jbird

3

No es del todo cierto en el caso de BasicDataSource.

Si lee los javadocs para BasicDataSource, setPassword() no tiene ningún efecto una vez que la agrupación se ha inicializado.El grupo se inicializa la primera vez que se invoca uno de los siguientes métodos: getConnection, setLogwriter, setLoginTimeout, getLoginTimeout, getLogWriter.

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

Todos estos métodos llaman createDataSource() con el tiempo.

Así que su nueva clase BasicDataSource sólo tiene que reemplazar el método createDataSource() Algo como esto:

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 
    } 
} 
Cuestiones relacionadas