While atempting to connect to a customer ATP using given crednetails resulted in an error similar to below.
java.sql.SQLException: the connection properties file contains an invalid expression in the value of: javax.net.ssl.keyStorePassword
The customer given credentail for the ATP wallet (which is also the passwords for key/trust store) contained the character "?".
After some investigations it was found out that the JDBC driver treats the "?" as a subtitue for $ORACLE_HOME and complains that this is not set.
Caused by: java.io.IOException: Environment variable is not set: ORACLE_HOME. ('?' is interpreted as $ORACLE_HOME) at oracle.jdbc.driver.PropertiesFileUtil$Interpreter.readQuestionMark(PropertiesFileUtil.java:702) at oracle.jdbc.driver.PropertiesFileUtil$Interpreter.interpret(PropertiesFileUtil.java:669) at oracle.jdbc.driver.PropertiesFileUtil$Interpreter.access$000(PropertiesFileUtil.java:622) at oracle.jdbc.driver.PropertiesFileUtil.processExpressions(PropertiesFileUtil.java:591)
Similar to keystore, the truststore also result in an error. Since JDBC driver code load keystore password first and as it result in an error the trusture password doesn't get picked. But if truststore password contains ? and keystore didn't then error would indicate the same with regard to truststore.
java.sql.SQLException: the connection properties file contains an invalid expression in the value of: javax.net.ssl.trustStorePassword
This could affect not just ATP but any DB. Infact to recreate the problem don't even need a DB to connect to. Simply loading a ojdbc.properties file with either keystore or truststore password containing "?" character in them would result in the error. Below is an example java class with minimum number of lines of code needed to recreate the issue. The DB URL need not be valid as error occurs before URL is validated.
public class KeyStorePwd2 { public static void main(String[] args) throws Exception { PoolDataSource ds = PoolDataSourceFactory.getPoolDataSource(); ds.setConnectionFactoryClassName("oracle.jdbc.pool.OracleDataSource"); ds.setURL("jdbc:oracle:thin:@test:1512/test"); Connection con = ds.getConnection(); } }
The ojdbc.properties contain the following
javax.net.ssl.trustStore=C:\\Asanga\\java\\keystoretest\\truststore.jks javax.net.ssl.trustStorePassword=test_123?4_ABC javax.net.ssl.keyStore=C:\\Asanga\\java\\keystoretest\\keystore.jks javax.net.ssl.keyStorePassword=test_123?4_ABCCompile and run giving the ojdbc.properties file location in the tns_admin JVM option.
java -Doracle.net.tns_admin=. KeyStorePwd2This result in a run time error and stack trace is shown below.
Exception in thread "main" java.sql.SQLException: Unable to start the Universal Connection Pool: oracle.ucp.UniversalConnectionPoolException: Cannot get Connection from Datasource: java.sql.SQLException: the connection properties file contains an invalid expression in the value of: javax.net.ssl.keyStorePassword at oracle.ucp.util.UCPErrorHandler.newSQLException(UCPErrorHandler.java:456) at oracle.ucp.util.UCPErrorHandler.throwSQLException(UCPErrorHandler.java:133) at oracle.ucp.jdbc.PoolDataSourceImpl.startPool(PoolDataSourceImpl.java:928) at oracle.ucp.jdbc.PoolDataSourceImpl.getConnection(PoolDataSourceImpl.java:1961) at oracle.ucp.jdbc.PoolDataSourceImpl.access$400(PoolDataSourceImpl.java:201) at oracle.ucp.jdbc.PoolDataSourceImpl$31.build(PoolDataSourceImpl.java:4279) at oracle.ucp.jdbc.PoolDataSourceImpl.getConnection(PoolDataSourceImpl.java:1917) at oracle.ucp.jdbc.PoolDataSourceImpl.getConnection(PoolDataSourceImpl.java:1880) at oracle.ucp.jdbc.PoolDataSourceImpl.getConnection(PoolDataSourceImpl.java:1865) at KeyStorePwd2.main(KeyStorePwd2.java:18) Caused by: oracle.ucp.UniversalConnectionPoolException: Cannot get Connection from Datasource: java.sql.SQLException: the connection properties file contains an invalid expression in the value of: javax.net.ssl.keyStorePassword at oracle.ucp.util.UCPErrorHandler.newUniversalConnectionPoolException(UCPErrorHandler.java:336) at oracle.ucp.util.UCPErrorHandler.throwUniversalConnectionPoolException(UCPErrorHandler.java:59) at oracle.ucp.jdbc.oracle.OracleDataSourceConnectionFactoryAdapter.createConnection(OracleDataSourceConnectionFactoryAdapter.java:134) at oracle.ucp.common.Database.createPooledConnection(Database.java:256) at oracle.ucp.common.Topology.start(Topology.java:247) at oracle.ucp.common.Core.start(Core.java:2361) at oracle.ucp.common.UniversalConnectionPoolBase.start(UniversalConnectionPoolBase.java:690) at oracle.ucp.jdbc.oracle.OracleJDBCConnectionPool.start(OracleJDBCConnectionPool.java:129) at oracle.ucp.jdbc.PoolDataSourceImpl.startPool(PoolDataSourceImpl.java:924) ... 7 more Caused by: java.sql.SQLException: the connection properties file contains an invalid expression in the value of: javax.net.ssl.keyStorePassword at oracle.jdbc.driver.PropertiesFileUtil.processExpressions(PropertiesFileUtil.java:596) at oracle.jdbc.driver.PropertiesFileUtil.loadDefaultFiles(PropertiesFileUtil.java:221) at oracle.jdbc.driver.PropertiesFileUtil.loadPropertiesFromFile(PropertiesFileUtil.java:139) at oracle.jdbc.driver.PhysicalConnection.getConnectionPropertiesFromFile(PhysicalConnection.java:10210) at oracle.jdbc.driver.PhysicalConnection.readConnectionProperties(PhysicalConnection.java:1049) at oracle.jdbc.driver.PhysicalConnection.init>(PhysicalConnection.java:747) at oracle.jdbc.driver.T4CConnection.<init>(T4CConnection.java:502) at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:56) at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:747) at oracle.jdbc.pool.OracleDataSource.getPhysicalConnection(OracleDataSource.java:413) at oracle.jdbc.pool.OracleDataSource.getConnection(OracleDataSource.java:298) at oracle.jdbc.pool.OracleDataSource$1.build(OracleDataSource.java:1730) at oracle.jdbc.pool.OracleDataSource$1.build(OracleDataSource.java:1716) at oracle.ucp.jdbc.oracle.OracleDataSourceConnectionFactoryAdapter.createConnection(OracleDataSourceConnectionFactoryAdapter.java:103) ... 13 more Caused by: java.io.IOException: Environment variable is not set: ORACLE_HOME. ('?' is interpreted as $ORACLE_HOME) at oracle.jdbc.driver.PropertiesFileUtil$Interpreter.readQuestionMark(PropertiesFileUtil.java:702) at oracle.jdbc.driver.PropertiesFileUtil$Interpreter.interpret(PropertiesFileUtil.java:669) at oracle.jdbc.driver.PropertiesFileUtil$Interpreter.access$000(PropertiesFileUtil.java:622) at oracle.jdbc.driver.PropertiesFileUtil.processExpressions(PropertiesFileUtil.java:591) ... 26 more
It makes no sense to treat "?" in a password field as a directory location i.e $ORACLE_HOME.
The issue is not there if the password doesn't contain "?". In case of ATP its just a matter of downloading a new wallet and giving it a password that doesn't contain "?" character in it.
However, if this is not possible there are several workarounds to overcome this.
One solution is to specify the keystore and trusttore password as JVM options instead of using ojdbc.properties file (key/trust sotre file location could still be loaded from ojdbc.properteis). Taking the previous example this would look like as below (it's assume password related lines are commented in the ojdbc.properties)
java -Doracle.net.tns_admin=. -Djavax.net.ssl.keyStorePassword=test_123?4_ABC -Djavax.net.ssl.trustStorePassword=test_123?4_ABC KeyStorePwd2
Other solution is to specify it as a connection pool property. Example sinppet shown below.
PoolDataSource ds = PoolDataSourceFactory.getPoolDataSource(); ds.setConnectionFactoryClassName("oracle.jdbc.pool.OracleDataSource"); Properties p = new Properties(); p.put(CONNECTION_PROPERTY_THIN_JAVAX_NET_SSL_TRUSTSTOREPASSWORD, "hello_DB?A_1234"); p.put(CONNECTION_PROPERTY_THIN_JAVAX_NET_SSL_KEYSTOREPASSWORD, "hello_DB?A_1234"); ds.setConnectionProperties(p);
SR has resulted in intenral bug 33473422.