Using encoded password for the datasource used in spring applicationContext.xml

Create customized PropertyPlaceHolderConfigurer extending Spring PropertyPlaceHolderConfigurer

public class PropertyPlaceholderConfigurer extends
        org.springframework.beans.factory.config.PropertyPlaceholderConfigurer {

    @Override
    protected String convertPropertyValue(final String originalValue) {
        if (originalValue.startwith("SomeText:")) {
            //Apply the decryption logic
            ...
        }
    }
}

You can encrypt the properties and append SomeText:. Use this customized PropertyPlaceHolderConfigurer to load the properties


Create a wrapper class implementing the Datasource interface which delegates it's method calls to the underlying datasource but decrypts the password before doing so.


Its might be funny that I am answering to my own question. but still I just wanted to tell my solution, others who might have faced same kind of issue..

for simplicity I have used BASE64Encoder & BASE64Decoder. later I will modify my code to use a secure/better encryption/decryption algorithm.

I have encoded my database password(ex: root for my case) by using the below code:

private String encode(String str) {
        BASE64Encoder encoder = new BASE64Encoder();
        str = new String(encoder.encodeBuffer(str.getBytes()));
        return str;
    }

and placed the encoded password in my database.properties file like below:

before

db.driverClassName=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost/myDB
db.username=root
db.password=root

after

db.driverClassName=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost/myDB
db.username=root
db.password=cm9vdA==  (Note: encoded 'root' by using BASE64Encoder)

Now I have written a wrapper class for org.apache.commons.dbcp.BasicDataSource and overridden setPassword() method:

import java.io.IOException;
import org.apache.commons.dbcp.BasicDataSource;
import sun.misc.BASE64Decoder;

public class MyCustomBasicDataSource extends BasicDataSource{

    public CustomBasicDataSource() {
        super();
    }

    public synchronized void setPassword(String encodedPassword){
        this.password = decode(encodedPassword);
    }

    private String decode(String password) {
        BASE64Decoder decoder = new BASE64Decoder();
        String decodedPassword = null;
        try {
            decodedPassword = new String(decoder.decodeBuffer(password));
        } catch (IOException e) {
            e.printStackTrace();
        }       
        return decodedPassword;
    }
}

This way I am decoding(BASE64Decoder) the encoded password provided in database.properties

and also modified the class attribute of my dataSource bean mentioned in springApplicationContext.xml file.

<beans:bean id="dataSource" class="edu.config.db.datasource.custom.MyCustomBasicDataSource" destroy-method="close">
    <beans:property name="driverClassName"><beans:value>${db.driverClassName}</beans:value></beans:property>
    <beans:property name="url"><beans:value>${db.url}</beans:value></beans:property>
    <beans:property name="username"><beans:value>${db.username}</beans:value></beans:property>
    <beans:property name="password"><beans:value>${db.password}</beans:value></beans:property>

Thanks.


I'd like to look at the larger picture here: why do you want to encrypt values in your properties file? What is your scenario where unauthorized people have access to your properties file?

A usual technique to deal with this larger problem of storing production credentials is to make credentials a part of your environment as opposed to part of your source code. Here are some ways to do this:

  • Placing the properties file (with plaintext passwords) on the classpath of the web server in production, this way access to that password is controlled by access to the production machine.
  • Store properties in web.xml (context-param with param-name), again this file is part of the environment in which you run your code and not distributed with your code - access to that file is controlled by access to the machine.
  • Use JNDI and configure that resource in your application server.