Как использовать зашифрованный пароль в apache BasicDataSource?
В настоящее время я храню пароль [незашифрованным] в файле свойств. Этот пароль размещается как есть в конфигурации xml с помощью ant.
[Конфигурация xml предназначена для источника данных, он создает объект dbcp.BasicDataSource ]
Теперь возможно, что после цели ant пароль будет скопирован в зашифрованном виде. Слышал, что Джасепт может это сделать! До сих пор я не пробовал это. Но проблема не заканчивается здесь. BasicDataSource не принимает зашифрованный пароль. Есть ли замена для BasicDatasource.
К вашему сведению: я использую Spring, если это имеет значение.
5 ответов
Создать новую задачу, расширив существующую задачу Copy
(ответственный за файл-копию). Создайте новый тип, расширяя FilterSet
(отвечает за фильтрацию токенов).
см. код здесь:- Как создать вложенный элемент для задачи муравья?
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>@CONNECTION_URL@</value>
</property>
<property name="username">
<value>@USERNAME@</value>
</property>
<property name="password">
<value>@PASSWORD@</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 ));
}
}
Все это;)
В 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 в заполнителе свойства, Spring загружает 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:
Jasypt предоставляет реализацию этих связанных с конфигурацией классов Spring, которые могут читать файлы.properties с зашифрованными значениями (например, те, которые управляются классом EncryptableProperties) и прозрачно обрабатывать их для остальных компонентов приложения Spring.
С этим вы можете определить 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>
Таким образом, вы можете поместить пароль для дешифрования скрытого свойства в переменную окружения при запуске приложения и удалении его позже.
Не совсем верно в случае BasicDataSource
,
Если вы читаете Javadocs для BasicDataSource
, setPassword()
не имеет эффекта после инициализации пула. Пул инициализируется при первом вызове одного из следующих методов: getConnection
, setLogwriter
, 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
}
}
Следующая ссылка jasypt объясняет, как файл свойств, содержащий зашифрованный контент, может быть прочитан из вашего приложения:
http://www.jasypt.org/encrypting-configuration.html
Чтобы создать файл свойств из ANT, я предлагаю использовать команду groovy следующим образом:
<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>
Расширьте BasicDataSource, переопределите методы setPassword и setUserName. Расшифруйте значения в этих методах и передайте их методам суперкласса.