We are facing issue with connecting to Postgres SQL database with certificate (pk8 and key file) in tomcat using Java web application, however when we try to connect with Java standalone we can able to connect.
Upon checking the Catalina logs we found the error –
org.postgresql.util.PSQLException: FATAL: connection requires a valid client certificate
Below is the connection params used in Java web application (as per documentation), the same works fine when tried with standalone application (Refer screen shot below)
jdbc:postgresql://:/<DB_NAME>?sslmode=require&sslcert=/app/localstorage/UAT_Certs/FA1234.crt&sslkey=/app/localstorage/UAT_Certs/FA1234.pk8&sslpassword=XXXX&user=XXXX
Standalone Successful connection:
java -cp postgresql-9.3-1102-jdbc41.jar:Query.jar com.company.test.Query
URL used to connect to Database is
jdbc:postgresql://example.com:5432/sample?sslmode=require&sslcert=/app/localstorage/FA1234.crt&sslkey=/app/localstorage/FA1234.pk8&sslpassword=test&user=test_name
Output:
Current Time in Database is 12:15:48.738587+01
Below is the code which we use in Tomcat to create Data source by passing the necessary DB information:
public class SecureTomcatDataSourceImpl extends DataSourceFactory {
private EncDecJDBCPass encryptor = null;
public SecureTomcatDataSourceImpl() {
try {
encryptor = new EncDecJDBCPass();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public DataSource createDataSource(Properties properties, Context context, boolean XA) throws InvalidKeyException,
IllegalBlockSizeException, BadPaddingException, SQLException, NoSuchAlgorithmException,
NoSuchPaddingException, UnrecoverableKeyException, KeyManagementException, CertificateException, FileNotFoundException, KeyStoreException, IOException {
System.out.println("Inside createDataSource() method. ");
//fetching pfx file encrypted password from context.xml
PoolConfiguration poolProperties = SecureTomcatDataSourceImpl.parsePoolProperties(properties);
//poolProperties.setPassword(pwd);
poolProperties.setPassword(null);
poolProperties.setUsername("XXXX");
String urlVal = poolProperties.getUrl();
System.out.println("Before Append"+urlVal);
String appendUrlVal = "jdbc:postgresql://:/<DB_NAME>?sslmode=require&sslcert=/app/localstorage/UAT_Certs/FA1234.crt&sslkey=/app/localstorage/UAT_Certs/FA1234.pk8&sslpassword=XXXX&user=XXXX"
System.out.println("AppendUrlVal:::::::::::::::"+appendUrlVal);
poolProperties.setUrl(appendUrlVal);
// The rest of the code is copied from Tomcat's DataSourceFactory.
if (poolProperties.getDataSourceJNDI() != null && poolProperties.getDataSource() == null) {
performJNDILookup(context, poolProperties);
}
org.apache.tomcat.jdbc.pool.DataSource dataSource = XA ? new XADataSource(poolProperties)
: new org.apache.tomcat.jdbc.pool.DataSource(poolProperties);
String Name = SecureTomcatDataSourceImpl.getProperties("name").toString();
String URL = poolProperties.getUrl();
System.out.println("URL VALUE::::::::"+URL);
String username = poolProperties.getUsername();
Logger.getLogger(SecureTomcatDataSourceImpl.class.getName()).log(Level.INFO, "Creating a New Connection Pool for DataSource "+Name+" with URL "+URL+" and the username "+username);
dataSource.createPool();
return dataSource;
}
}
Code used in Standalone Program:
import java.sql.*;
import java.util.Properties;
public class Query {
public static void main(String[] args) {
try {
String url = "jdbc:postgresql://:/<DB_NAME>?sslmode=require&sslcert=/app/localstorage/UAT_Certs/FA1234.crt&sslkey=/app/localstorage/UAT_Certs/FA1234.pk8&sslpassword=XXXX&user=XXXX"
System.out.println("URL used to connect to Database is " + url);
Connection conn = DriverManager.getConnection(url);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select current_time");
while (rs.next()) {
System.out.println("Current Time in Database is :::::::::::::::::::::::::" + rs.getString("current_time"));
}
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}