STEP 1 : Download Jasypt
We are going to use jasypt for sensitive data encryption and decryption , you may download command line tool from http://www.jasypt.org.
STEP 2 : Encrypt Your Credentials
After downloading jasypt, extract the zip file anywhere and go into bin folder run below commands :
$ ./encrypt.sh input="your-db-user" password=secret-key
$ ./encrypt.sh input="your-db-password" password=secret-key
$ ./encrypt.sh input="your-db-url" password=secret-key
"secret-key" would be needed for decryption, so you need to keep it safe and in this post we are storing and retrieving the secret key from system enviroment variable.
STEP 3 : Configure Your Datasource
Use encrypted values in step 2 to configure your secured datasource in context.xml as below :
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version='1.0' encoding='utf-8'?> | |
<Context> | |
<Resource name="jdbc/yourDB" | |
auth="Container" | |
type="javax.sql.DataSource" | |
driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver" | |
factory="org.junjun.util.secured.resources.datasource.EncryptedDataSourceFactory" | |
url="e6nNC2NVXThPKSyKMvCiZTa4beL/BHxyu+188EeeNWq10ynepC2f4fXHzlKKdo9288uNOStZwa6Ztu0h7TrWVAJIrurKQkfO" | |
username="PzyHPd4xkXJYvoN6ztoLWg==" | |
password="zeBxd99nNw2Hg6f4g/Rt8PkB7+uHOwVD" | |
maxActive="20" | |
maxIdle="10" | |
maxWait="-1" /> | |
<ResourceLink name="jdbc/yourDB" global="jdbc/yourDB" type="javax.sql.DataSource" /> | |
</Context> |
STEP 4 : Create Your Own Datasource Factory
As you can see from step 3 we add an attribute "factory" to "Resource" tag which is going to be used to initialise the datasource in the same time decrypt database connection credentials.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.junjun.util.secured.resources.datasource; | |
import java.util.Enumeration; | |
import java.util.Hashtable; | |
import javax.naming.Context; | |
import javax.naming.Name; | |
import javax.naming.RefAddr; | |
import javax.naming.Reference; | |
import javax.naming.StringRefAddr; | |
import org.apache.commons.dbcp.BasicDataSourceFactory; | |
import org.jasypt.encryption.pbe.StandardPBEStringEncryptor; | |
public class EncryptedDataSourceFactory extends BasicDataSourceFactory { | |
private String USERNAME_TAG = "username"; | |
private String PASSWORD_TAG = "password"; | |
private String URL_TAG = "url"; | |
private StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor(); | |
private String password = System.getenv("secret-key"); | |
public EncryptedDataSourceFactory() { | |
encryptor.setPassword(this.password); | |
} | |
@Override | |
public Object getObjectInstance(Object obj, Name name, Context ctx, Hashtable env) throws Exception { | |
if (obj instanceof Reference) { | |
setUsername((Reference) obj); | |
setPassword((Reference) obj); | |
setURL((Reference) obj); | |
} | |
return super.getObjectInstance(obj, name, ctx, env); | |
} | |
private void setUsername(Reference ref) { | |
findDecryptAndReplace(USERNAME_TAG, ref); | |
} | |
private void setPassword(Reference ref) { | |
findDecryptAndReplace(PASSWORD_TAG, ref); | |
} | |
private void setURL(Reference ref) { | |
findDecryptAndReplace(URL_TAG, ref); | |
} | |
private void findDecryptAndReplace(String refType, Reference ref) { | |
Integer idx = find(refType, ref); | |
if (idx == null) { | |
System.out.println("The \"" + refType + "\" name/value pair was not found" | |
+ " in the Reference object. The reference Object is" + " " + ref.toString()); | |
} else { | |
String decrypted = decrypt(ref.get(refType).getContent().toString()); | |
replace(idx, refType, decrypted, ref); | |
} | |
} | |
private void replace(int idx, String refType, String newValue, Reference ref) { | |
ref.remove(idx); | |
ref.add(idx, new StringRefAddr(refType, newValue)); | |
} | |
private String decrypt(String input) { | |
return encryptor.decrypt(input); | |
} | |
private Integer find(String addrType, Reference ref) { | |
Integer index = null; | |
Enumeration<RefAddr> enu = ref.getAll(); | |
for (int i = 0; enu.hasMoreElements(); i++) { | |
RefAddr addr = (RefAddr) enu.nextElement(); | |
if (addr.getType().compareTo(addrType) == 0) | |
index = i; | |
} | |
return index; | |
} | |
} |
STEP 5 : Build Your Own Datasource Factory into a Jar File
Please refer to https://github.com/junjun-dachi/java-util/tree/master/secured-resources-util for the maven project which contains source code of EncryptedDataSourceFactory.
Build "secured-resources-util" project with maven , system would generate a jar file named "secured-resources-1.0.jar".
STEP 6 : Copy Jar Files to Tomcat
You would need to copy below jar file to ${tomcat_dir}/lib in order to have the code running.
1. jasypt-1.9.2.jar
2. sqljdbc42.jar
3. commons-dbcp-1.4.jar
4. commons-pool-1.5.4.jar
5. secured-resources-1.0.jar
STEP 7 : Datasource Injection
In the application code you may inject the datasource as below:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
DataSource ds = null; | |
JndiTemplate jndi = new JndiTemplate(); | |
try { | |
ds = jndi.lookup("java:comp/env/jdbc/yourDB", DataSource.class); | |
} catch (NamingException e) { | |
log.error("NamingException for java:comp/env/jdbc/yourDB", e); | |
} |
JOB DONE
No comments:
Post a Comment