dwipin chandran
dwipin chandran

Reputation: 31

access a property within a custom PropertyPlaceholderConfigurer

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

Answers (2)

Cristina_eGold
Cristina_eGold

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

Thierry
Thierry

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

Related Questions