Reputation: 31
We are on Spring 4.2.5 version. There is a need to have a custom implementation of PropertyPlaceholderConfigurer basically to have data decrypted before using them. This works fine. However I further need to be able to change the crypto mechanism used within this custom implementation, based on a property (read using the normal context:property-placeholder). Is there a way to get this working?
Upvotes: 3
Views: 1115
Reputation: 1553
Your use case is covered by the jasypt
library, if you don't mind adding one more dependency to your project. What makes it neat is the fact that it integrates seamlessly with Spring and it facilitates further changes in the parameterization of your encryption, i.e. the algorithm used or the location of the master encryption key.
What is cool is that the code in your spring config / class annotations, in which you inject the value corresponding to a certain key in a property file, will look the same, as if you're using plain-text properties.
Here is a small example, as per the tutorial in their website (http://www.jasypt.org/spring31.html):
application.properties => your properties file
datasource.driver=com.mysql.jdbc.Driver
datasource.url=jdbc:mysql://localhost/reportsdb
datasource.username=reportsUser
datasource.password=ENC(G6N718UuyPE5bHyWKyuLQSm02auQPUtm)
your Spring config (works the same when injecting through annotations)
<!-- -->
<!-- Configuration for encryptor, based on environment variables. -->
<!-- -->
<!-- In this example, the encryption password will be read from an -->
<!-- environment variable called "APP_ENCRYPTION_PASSWORD" which, once -->
<!-- the application has been started, could be safely unset. -->
<!-- -->
<bean id="environmentVariablesConfiguration"
class="org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig">
<property name="algorithm" value="PBEWithMD5AndDES" />
<property name="passwordEnvName" value="APP_ENCRYPTION_PASSWORD" />
</bean>
<!-- -->
<!-- The will be the encryptor used for decrypting configuration values. -->
<!-- -->
<bean id="configurationEncryptor"
class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor">
<property name="config" ref="environmentVariablesConfiguration" />
</bean>
<!-- -->
<!-- The EncryptablePropertyPlaceholderConfigurer will read the -->
<!-- .properties files and make their values accessible as ${var}. -->
<!-- -->
<!-- Our "configurationEncryptor" bean (which implements -->
<!-- org.jasypt.encryption.StringEncryptor) is set as a constructor arg. -->
<!-- -->
<bean id="propertyConfigurer"
class="org.jasypt.spring31.properties.EncryptablePropertyPlaceholderConfigurer">
<constructor-arg ref="configurationEncryptor" />
<property name="locations">
<list>
<value>/WEB-INF/classes/application.properties</value>
</list>
</property>
</bean>
<!-- -->
<!-- Our datasource is configured here, in the usual way. Jasypt's -->
<!-- EncryptedPropertyPlaceholderConfigurer will make sure that the -->
<!-- ${datasource.password} file gets decrypted and the DBCP DataSource -->
<!-- will be correctly initialised. -->
<!-- -->
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName">
<value>${datasource.driver}</value>
</property>
<property name="url">
<value>${datasource.url}</value>
</property>
<property name="username">
<value>${datasource.username}</value>
</property>
<property name="password">
<value>${datasource.password}</value>
</property>
</bean>
Jasypt parses the content of the property files you've provided and decrypts the values enclosed between ENC(
and )
. You can find additional details in the link provided above, it is truly a working example.
Another interesting feature of jasypt
is the fact that it provides a command line tool
, that you can use to encrypt the original, plain-text values, with a plethora of algorithms you can choose from. You can find the concise documentation of this tool here: http://www.jasypt.org/cli.html.
Upvotes: 0
Reputation: 5440
The easiest way to do that is not to have a custom PropertyPlaceholderConfigurer
, but a custom DefaultPropertiesPersister
. This is configured this way :
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:...</value>
<value>...</value>
</list>
</property>
<property name="propertiesPersister">
<bean class="yourPropertiesPersister"/>
</property>
...
</bean>
Then yourPropertiesPersister
needs to extends DefaultPropertiesPersister
which makes you implement :
public void load(Properties props, InputStream is) throws IOException {
super.load(props, is);
decrypt(props);
}
@Override
public void load(Properties props, Reader reader) throws IOException {
super.load(props, reader);
decrypt(props);
}
private void decrypt(Properties props) {
// your logic here
}
The call to super.load(...)
will load the raw properties (content is not decrypted). Just add the logic to a method decrypt(props)
, based on the content of some of the properties. Add your decrypted properties to props
.
Upvotes: 1