Welcome!

Java Authors: Don MacVittie, Maureen O'Gara, Liz McMillan, Walter H. Pinson, III, Yakov Werde

Related Topics: Java

Java: Article

How to Secure Tomcat Database Passwords for Java

In production environments there are features of Tomcat that don't pass security audit reviews

Tomcat creates an instance of BasicDataSourceFactory by calling its no-argument constructor. When a DataSource is needed the getObjectInstance(...) method is called. The BasicDataSourceFactory class implements this method in the following way. First it typecasts the Object parameter to Reference. Then all of the name/value pairs are removed from the Reference object and set in a Properties object. Finally, the Properties object is passed to the createDataSource(...) method where it's assumed the username and password exist in the Properties object as clear text.

To secure Tomcat database usernames and passwords, create a new class named EncryptedDataSourceFactory that extends BasicDataSourceFactory. This new class is going to override the getObjectInstance(...) method. The new method is implemented in the following way. First it will remove the encrypted username and passwords from the Reference object. Next, it will decrypt them. Then it will put the decrypted values into the Reference object. Finally it will call the getObjectInstance(...) method of the super class so it can take care of creating the DataSource. See the source code in Listing 3.

In the source code the "username" string of the setUsername() method and the "password" string of the setPassword() method refer to the <name/> value of:

<parameter>
     <name>username</name>
     <value>postgres_user</value>
   </parameter>
   <parameter>
     <name>password</name>
     <value>postgres_pass</value>
   </parameter>

These strings have corresponding constants in the BasicDataSourceFactory class but the constants are declared private so can't be used. The find() method throws an exception if not found because decryption will fail if there's nothing to decrypt. The decrypt() method uses a Base64 decoder that isn't secure but adequately demonstrates the concept. Finally the replace() method removes the encrypted values and puts in the decrypted values. When getObjectInstance(...) of the super class is called, it has the clear text passwords and is completely unaware that the values in server.xml are actually encrypted.

Using EncryptedDataSourceFactory is simple. First drop the org.moss.jdj.jdbc-yyyy.mm.dd.x.jar file into TOMCAT/server/lib. Next, get a Base64 encoding of the username and password. A simple Yahoo! search of "online base64 encoder" will find sites that will do it. Finally, edit server.xml and replace the username and password values with their corresponding Base64 equivalents and set the factory value to org.moss.jdj.dbcp.EncryptedDataSourceFactory. Start up Tomcat and see it in action.

Using Tomcat's built-in extensibility like this is an attractive solution. It fulfills security audit requirements by removing clear text usernames and passwords but it also lets applications be coded to EE specs. Using this solution doesn't put any unnecessary or unwanted responsibility in applications. Applications can be developed to fulfill business requirements and don't have to worry about plumbing code like initializing or shutting down a database connection pool properly, maintaining a custom transaction system to roll back on errors, or implementing an encryption strategy. Plus, when the time comes to move away from Tomcat the applications will be ready. The code in Listing 3 will be thrown away but small amounts of throwaway code is much better than the effort needed to go back and update applications.

More Stories By Michael Remijan

Michael J. Remijan is a research programmer at the National Center for Supercomputing Applicaitons (NCSA). His chief responsibilities include data miming and access to terabyte-sized astronomy data sets. Michael received a BS in mathematics and computer science from the University of Illinois and is currently working on an MBA in technology management.

Comments (10) View Comments

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.


Most Recent Comments
sn72 11/09/08 09:26:48 PM EST

A similar solution is to create a MySQL driver. That is, create a class derived from com.mysql.jdbc.NonRegisteringDriver. Create a static initializer block to register the class with java.sql.DriverManager, following the example in com.mysql.jdbc.Driver. Override the following functions:

public Connection connect(String string, Properties properties) throws SQLException

public boolean acceptsURL(String string) throws SQLException

In the connect function lookup the username and pasword in the properties using 'user' and 'password'. Decrypt the password (maybe there can be a different algorithm for each user). Install the decrypted password back into 'properties'.

One advantage of this solution is that you can use the custom driver with standalone JUnit tests and swing code.

Chris 04/19/08 10:49:36 AM EDT

Hi Michael,

thanks a lot. That was the stuff we needed. You saved me a lot of hours having headache about this stuff. May be you will submit your code to apache. I missed this functionality baddly in commons-dbcp.

Once again thanks a lot.
Best wishes from austria.

Chris

Fret 10/05/07 12:15:08 PM EDT

Would this work in Glassfish also?

Pavel Buzek 10/04/07 02:00:57 PM EDT

Just a technical correction: the article says "Tomcat is a great reference implementation of the Java EE specification" ... well, of course it isn't. Tomcat is not even an implementation of Java EE spec (only a small subset of it) so it cannot be the reference impl, which is [https://glassfish.dev.java.net/].

Wayne 10/03/07 10:28:24 AM EDT

Michael,

This posting was exactly what I needed. Thank you Thank you Thank you !!!

Rob 09/11/07 04:44:26 PM EDT

The third solution is very interesting, but a bit vague on a key detail.

How are you proposing you encrypt this data? Are you storing the encryption key were the tomcat server has access to it in clear text? As long as that is so there is still no secret, just an extra hurdle.

Suilong 08/28/07 10:35:09 AM EDT

very helpful article. thank you

Madhu 08/02/07 10:20:07 AM EDT

Hi Michael,

Your article is great and helped me since it was exactly what I needed.

The documentation for implementation in supplemental download requires the use of org.moss.jdj.dbcp-yyyy.mm.dd.jar. It provides a link to the location of that jar in the download, but the jar is not there. Is there some other location I can download the jar from?

Thank you.

Rafael 07/31/07 11:01:13 AM EDT

Michael,

may I use the third example you provided the same way when specifying my connection parameters in an xml file located at
%TOMCAT_HOME%/conf/catalina/localhost/myApp.xml?

Regards

ebuild 07/31/07 10:41:51 AM EDT

You said :
" Tomcat is a great reference implementation of the Java EE..."
Be more accurate, Tomcat is the first reference implementation of Servlet specification.