Play 2.4 HikariCP connection pool configuration - java

I need to specify some config parameters, separated by dots. Connection pool is in Play 2.4 application. For example
db {
default {
driver = ${?DB_DRIVER}
url = ${?DB_URL}
username = ${?DB_USER}
password = ${?DB_PASSWORD}
hikaricp {
dataSource {
"javax.net.ssl.trustStore" = ${?DB_TRUST_STORE}
"javax.net.ssl.trustStoreType" = "JKS"
"javax.net.ssl.trustStorePassword" = ${?DB_TRUST_STORE_PASSWORD}
"javax.net.ssl.keyStore" = ${?DB_KEY_STORE}
"javax.net.ssl.keyStoreType" = "JKS"
"javax.net.ssl.keyStorePassword" = ${?DB_KEY_STORE_PASSWORD}
}
}
}
All parameters like "javax.net.ssl." are used to provide details about SSL certificates for connection. Looks like Play framework is trying to parse config keys like "javax.net.ssl." and separate them by dots. So it fails with the exception
Caused by: com.typesafe.config.ConfigException$Missing: No configuration setting found for key 'javax'
I found a similar topic here: How do I get an unwrapped key in Typesafe Config?
According to the first response
foo {
bar {
baz = 10
}
}
is the same as
foo.bar.baz = 10
But it would be different if written as "foo.bar.baz" = 10
I hoped that using quotes should help but it doesn't and seems like a bug in the pool configuration implementation. Please, advise.

I answer to complete #brettw answer.
You have to add these parameters as JVM properties when running your play exec :
/path/to/bin/<project-name>
-Djavax.net.ssl.keyStore=/mysql-credentials/keystore \
-Djavax.net.ssl.keyStorePassword=YYYYYY \
-Djavax.net.ssl.trustStore=/mysql-credentials/truststore \
-Djavax.net.ssl.trustStorePassword=XXXXXX \
...
For those wondering how to create these stores : read this
I think that trustStoreType and keyStoreType are not required, I always use JKS types.
Keep in mind that you also have to tell jdbc to use SSL :
-Dslick.dbs.default.db.url=jdbc:mysql://DOMAIN_OR_IP/DATABASE?verifyServerCertificate=false&useSSL=true&requireSSL=true
Last but not least you can debug the handshakes with :
-Djavax.net.debug=all
It gives you a lot (MB) of informations on handshakes, renegociation and ciphers printed on stdout

These are typically JVM properties, do I don't know if it is appropriate to put them in the db/dataSource configuration. Even if it is the driver that uses these, those are system-wide properties and would apply to all SSL components.

Related

Using OS system variable for #DataSourceDefinition password failed in Wildfly 18

I want to externalize password for Java #DataSourceDefinition using OS system variable ${appuserpwd}. The below is my #DataSourceDefinition
#DataSourceDefinition(
name = "java:app/jdbc/mydb",
className = "com.mysql.cj.jdbc.MysqlConnectionPoolDataSource",
portNumber = 3306,
serverName = "localhost",
databaseName = "mydb",
user = "appuser",
password = "${appuserpwd}",
isolationLevel = Connection.TRANSACTION_READ_COMMITTED,
properties = {})
I am using Wildfly 18. In subsystem ee, I already turn on these properties:
Annotation Property Replacement: ON
JBoss Descriptor Property Replacement: ON
Spec Descriptor Property Replacement: ON
I always get an Exception error as below:
Caused by: java.sql.SQLException: Access denied for user 'appuser'#'localhost' (using password: YES)
It means Wildfly failed to translate ${appuserpwd} to the real password from OS system environment named appuserpwd.
I have tried ${env.appuserpwd} for #DataSourceDefinition password but I got the same message.
If I replace ${appuserpwd} by the appuser real password -> The app works OK, no issues.
Any helps? Thanks!
There was a Java EE 7 spec proposal to support password aliasing, but it never made it into the specification. So there is no way to replace variables in a standard and portable (working on each Java EE compliant server) way.
Fortunately, the different application servers offer their own solution to achieve this.
For Wildfly you have to first enable annotation property replacement inside your standalone.xml:
<subsystem xmlns="urn:jboss:domain:ee:5.0">
<annotation-property-replacement>true</annotation-property-replacement>
</subsystem>
Now you can start replacing variables (syntax is ${ENV_VARIABLE:default}):
#DataSourceDefinition(
name = "java:app/jdbc/pqsql",
className = "org.postgresql.xa.PGXADataSource",
user = "${DB_USER:postgres}",
password = "${DB_PASSWORD:password}",
serverName = "${DB_SERVERNAME:localhost}",
portNumber = 5432,
databaseName = "${DB_DATABASENAME:testdatabase}")
You can find further information here.
UPDATE: I tried this with a recent Wildfly version (20.0.0.Final) and it seems there is a bug when replacing annotation variables. As a fallback you can use the traditional way of specifying the datasource using the Jboss CLI and use environment variables as expected:
# First create the new module for the JDBC driver
/subsystem=datasources/jdbc-driver=postgresql:add(driver-name=postgresql, driver-module-name=org.postgresql, driver-class-name=org.postgresql.Driver, driver-datasource-class-name=org.postgresql.ds.PGPoolingDataSource)
# Create a data source
/subsystem=datasources/data-source=PostgresDS:add(jndi-name=java:jboss/datasources/postgres, driver-name=postgresql, connection-url=jdbc:postgresl://localhost:5432/postgres, user-name=postgres, password=postgres)

Redisson Client with Sentinel throws exception

I'm using Redisson with below configuration to connect to Sentinel servers:
Config config = new Config();
config.useSentinelServers().setMasterName("local")
.addSentinelAddress("redis://localhost:26379", "redis://localhost:26380", "redis://localhost:26381");
RedissonClient client = Redisson.create(config);
How ever when I run this code I get the below error creating the client:
Caused by: java.lang.IllegalArgumentException: port out of range:-1
at java.net.InetSocketAddress.checkPort(InetSocketAddress.java:143)
at java.net.InetSocketAddress.<init>(InetSocketAddress.java:224)
at org.redisson.client.RedisClient.<init>(RedisClient.java:105)
at org.redisson.connection.MasterSlaveConnectionManager.createClient(MasterSlaveConnectionManager.java:354)
at org.redisson.connection.SentinelConnectionManager.<init>(SentinelConnectionManager.java:74)
at org.redisson.config.ConfigSupport.createConnectionManager(ConfigSupport.java:258)
at org.redisson.Redisson.<init>(Redisson.java:115)
at org.redisson.Redisson.create(Redisson.java:154)
I wanted to know if I'm missing any thing in the redisson config or my sentinel servers are not configured well.
Apologies for the confusion I have caused in editing the wiki. I should have stated that was in reflection to the latest version.
From 2.9.3 and 3.4.3 above, we have introduced the support for SSL, it is then required to specify the URI scheme to inform the type of connection that is requires.
It is working now if I change the original configuration as below:
Config config = new Config();
config.useSentinelServers().setMasterName("local")
.addSentinelAddress("localhost:26379", "localhost:26380", "localhost:26381");
RedissonClient client = Redisson.create(config);
It is misleading in the documentation as it does suggests otherwise.
https://github.com/redisson/redisson/wiki/2.-Configuration#271-sentinel-settings

Remote access to Message Queue over SSL in GlassFish

I'm trying to access a Message Queue configured in GlassFish but have been facing a lot of problems. The first one is regarding the Trust Store password on the client side. I can only make it work if I use the default password (changeit), I'm always getting
Keystore was tampered with, or password was incorrect
if I try to use a different password. And yes, I'm pretty sure I'm using the correct password.
In fact, if I set the Trust Store with the default password and use the following property with a wrong value, it still works:
-Djavax.net.ssl.trustStorePassword=<wrong value>
Which leads me to conclude that it completely ignores this setting.
This is what I've so far:
System.setProperty("com.sun.CSIV2.ssl.standalone.client.required", "true");
System.setProperty("javax.net.ssl.trustStore", "<my path>/truststore.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "<my password>");
Properties properties = new Properties();
System.setProperty("org.omg.CORBA.ORBInitialHost", "localhost");
System.setProperty("org.omg.CORBA.ORBInitialPort", "3820");
InitialContext ctx = new InitialContext(properties);
com.sun.messaging.ConnectionFactory connectionFactory = new com.sun.messaging.ConnectionFactory();
connectionFactory.setProperty(ConnectionConfiguration.imqAddressList, "127.0.0.1:7676");
connectionFactory.setProperty(ConnectionConfiguration.imqDefaultUsername, "<app user>");
connectionFactory.setProperty(ConnectionConfiguration.imqDefaultPassword, "<app user password>");
QueueConnection queueConnection = connectionFactory.createQueueConnection();
queueConnection.start();
So, my first question is: How can I use the non-default password on my Trust Store? Do I have to use some kind of encoding/hashing on the value?
My second question is regarding authentication. The standard way of getting the Connection Factory (via JNDI) and authenticate (via createQueueConnection(user, pass)) does not seem to be working, it always tries to use the guest account. Is there a way to use the standard approach on GlassFish or am I limited to use proprietary code?
EDIT #1
After digging a little deeper, I've detected a behavior that seems a bug.
Looking at the stacktrace, one of the first methods being invoked is initJKS() from com.sun.enterprise.security.ssl.impl.SecuritySupportImpl. With the help of javassist, I realized that the following section is being invoked:
if (masterPasswordHelper == null && Globals.getDefaultHabitat() != null) {
masterPasswordHelper = Globals.getDefaultHabitat().getByType(MasterPasswordImpl.class);
}
if (masterPasswordHelper instanceof MasterPasswordImpl) {
keyStorePass = masterPasswordHelper.getMasterPassword();
trustStorePass = keyStorePass;
}
Causing the bypass of the next set of instructions:
if (keyStorePass == null) {
keyStorePass = System.getProperty(KEYSTORE_PASS_PROP, DEFAULT_KEYSTORE_PASS).toCharArray();
trustStorePass = System.getProperty(TRUSTSTORE_PASS_PROP, DEFAULT_TRUSTSTORE_PASS).toCharArray();}
And, as a consequence, to ignore the property javax.net.ssl.trustStorePassword. Why is Globals.getDefaultHabitat() returning a non null value?

java ignores proxy settings

I have set up a local proxy server for request logging but my java code ignores it and connects directly (Windows XP, JDK 1.7). Web browsers work with it. So I wrote test code for discussion that seems to connect directly even if a (bogus) proxy is specified. With the bogus proxy, I would expect connection failure but the code succeeds, connecting directly:
System.setProperty("http.proxyHost", "localhost");
System.setProperty("http.proxyPort", "12345");
System.setProperty("http.nonProxyHosts", "noNonProxyHost.com");
URL url = new URL("http://docs.oracle.com/javase/7/docs/technotes/guides/net/proxies.html");
InputStream in = url.openStream();
System.out.println("Connection via bogus proxy succeeded");
The code is run as standalone Java, no Maven, no applet, no container. I have a direct internet connection.
In your case using java.net.URL(), if the proxy server cannot be reached at http.proxyHost and http.proxyPort then it simply falls back and tries to do a direct connect. If that succeeds, you'll see no exception thrown which is why your code works without error. You should see a pause while it tries to find the proxy though.
This sample code below happily fetches the URL and displays it, without error, even when run with bogus proxy settings. -Dhttp.proxyHost=bogus -Dhttp.proxyPort=2345 but will talk to my local proxy localhost port 8888 if set correctly
import java.io.*;
import java.net.URL;
import java.util.*;
public class URLClient {
private static String sUrl = "http://www.apache.org/";
public static void main(String[] args) {
try {
URL url = new URL(sUrl);
InputStream is = url.openStream();
java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
String output = s.hasNext() ? s.next() : "";
System.out.println(output);
} catch(Throwable e) {
System.err.println("exception");
}
}
}
The problem I was originally having with http.proxyHost and http.proxyPort being ignored (Google led me to your question) was that those settings are completely ignored by apache.commons.httpClient because it uses its own sockets, as described here.
http://cephas.net/blog/2007/11/14/java-commons-http-client-and-http-proxies/
I have faced a similar problem recently. First of all, one part of the above answer from Daemon42 explains pretty well, why the bogus proxy server didn't lead to a failure of the program:
if the proxy server cannot be reached at http.proxyHost and http.proxyPort then it simply falls back and tries to do a direct connect. If that succeeds, you'll see no exception thrown which is why your code works without error. You should see a pause while it tries to find the proxy though.
Still, your actual question was, why the proxy server configured via the operating system is not used by the Java application. As stated in the Oracle documentation (https://docs.oracle.com/javase/8/docs/technotes/guides/net/proxies.html), the system proxy settings are not evaluated by Java by default. To do so, you have to set the value of the system property "java.net.useSystemProxies" to the value "true".
You can set that system property on the command line, or you can edit the JRE installation file jre/lib/net.properties, that way you have to change it only once on a given system.

Java Client For Secure Hbase

Hi I am trying to write a java client for secure hbase.
I want to do kinit also from code itself for that i`m using the usergroup information class.
Can anyone point out where am I going wrong here?
this is the main method that Im trying to connect o hbase from.
I have to add the configuration in the CONfiguration object rather than using the xml, because the client can be located anywhere.
Please see the code below:
public static void main(String [] args) {
try {
System.setProperty(CommonConstants.KRB_REALM, ConfigUtil.getProperty(CommonConstants.HADOOP_CONF, "krb.realm"));
System.setProperty(CommonConstants.KRB_KDC, ConfigUtil.getProperty(CommonConstants.HADOOP_CONF,"krb.kdc"));
System.setProperty(CommonConstants.KRB_DEBUG, "true");
final Configuration config = HBaseConfiguration.create();
config.set(CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHENTICATION, AUTH_KRB);
config.set(CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHORIZATION, AUTHORIZATION);
config.set(CommonConfigurationKeysPublic.FS_AUTOMATIC_CLOSE_KEY, AUTO_CLOSE);
config.set(CommonConfigurationKeysPublic.FS_DEFAULT_NAME_KEY, defaultFS);
config.set("hbase.zookeeper.quorum", ConfigUtil.getProperty(CommonConstants.HBASE_CONF, "hbase.host"));
config.set("hbase.zookeeper.property.clientPort", ConfigUtil.getProperty(CommonConstants.HBASE_CONF, "hbase.port"));
config.set("hbase.client.retries.number", Integer.toString(0));
config.set("zookeeper.session.timeout", Integer.toString(6000));
config.set("zookeeper.recovery.retry", Integer.toString(0));
config.set("hbase.master", "gauravt-namenode.pbi.global.pvt:60000");
config.set("zookeeper.znode.parent", "/hbase-secure");
config.set("hbase.rpc.engine", "org.apache.hadoop.hbase.ipc.SecureRpcEngine");
config.set("hbase.security.authentication", AUTH_KRB);
config.set("hbase.security.authorization", AUTHORIZATION);
config.set("hbase.master.kerberos.principal", "hbase/gauravt-namenode.pbi.global.pvt#pbi.global.pvt");
config.set("hbase.master.keytab.file", "D:/var/lib/bda/secure/keytabs/hbase.service.keytab");
config.set("hbase.regionserver.kerberos.principal", "hbase/gauravt-datanode2.pbi.global.pvt#pbi.global.pvt");
config.set("hbase.regionserver.keytab.file", "D:/var/lib/bda/secure/keytabs/hbase.service.keytab");
UserGroupInformation.setConfiguration(config);
UserGroupInformation userGroupInformation = UserGroupInformation.loginUserFromKeytabAndReturnUGI("hbase/gauravt-datanode2.pbi.global.pvt#pbi.global.pvt", "D:/var/lib/bda/secure/keytabs/hbase.service.keytab");
UserGroupInformation.setLoginUser(userGroupInformation);
User user = User.create(userGroupInformation);
user.runAs(new PrivilegedExceptionAction<Object>() {
#Override
public Object run() throws Exception {
HBaseAdmin admins = new HBaseAdmin(config);
if(admins.isTableAvailable("ambarismoketest")) {
System.out.println("Table is available");
};
HConnection connection = HConnectionManager.createConnection(config);
HTableInterface table = connection.getTable("ambarismoketest");
admins.close();
System.out.println(table.get(new Get(null)));
return table.get(new Get(null));
}
});
System.out.println(UserGroupInformation.getLoginUser().getUserName());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
I`m getting the following exception:
Caused by: org.apache.hadoop.ipc.RemoteException(javax.security.sasl.SaslException): GSS initiate failed
at org.apache.hadoop.hbase.security.HBaseSaslRpcClient.readStatus(HBaseSaslRpcClient.java:110)
at org.apache.hadoop.hbase.security.HBaseSaslRpcClient.saslConnect(HBaseSaslRpcClient.java:146)
at org.apache.hadoop.hbase.ipc.RpcClient$Connection.setupSaslConnection(RpcClient.java:762)
at org.apache.hadoop.hbase.ipc.RpcClient$Connection.access$600(RpcClient.java:354)
at org.apache.hadoop.hbase.ipc.RpcClient$Connection$2.run(RpcClient.java:883)
at org.apache.hadoop.hbase.ipc.RpcClient$Connection$2.run(RpcClient.java:880)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:396)
at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1491)
at org.apache.hadoop.hbase.ipc.RpcClient$Connection.setupIOstreams(RpcClient.java:880)
... 33 more
Any pointers would be helpful.
The above works nicely, but I've seen a lot of folks struggle with setting all of the right properties in the Configuration object. There's no de-facto list that I've found of exactly what you need and don't need and it is painfully dependent on your cluster configuration.
The surefire way is to have a copy of your HBase configurations in your classpath, since your client can be anywhere as you mentioned. Then you can add the resources to your object without having to specify all properties.
Configuration conf = HBaseConfiguration.create();
conf.addResource("core-site.xml");
conf.addResource("hbase-site.xml");
conf.addResource("hdfs-site.xml");
Here were some sources to back this approach:
IBM,
Scalding (Scala)
Also note that this approach doesn't limit you to actually use the internal Zookeeper principal and keytab, i.e. you can create keytabs for applications or Active Directory users and leave the internally generated keytabs for the daemons to authenticate amongst themselves.
Not sure if you still need help. I think setting the "hadoop.security.authentication" property is missing from your snippet.
I am using following code snippet to connect to secure HBase (on CDH5). You can give a try.
config.set("hbase.zookeeper.quorum", zookeeperHosts);
config.set("hbase.zookeeper.property.clientPort", zookeeperPort);
config.set("hadoop.security.authentication", "kerberos");
config.set("hbase.security.authentication", "kerberos");
config.set("hbase.master.kerberos.principal", HBASE_MASTER_PRINCIPAL);
config.set("hbase.regionserver.kerberos.principal", HBASE_RS_PRINCIPAL);
UserGroupInformation.setConfiguration(config);
UserGroupInformation.loginUserFromKeytab(ZOOKEEPER_PRINCIPAL,ZOOKEEPER_KEYTAB);
HBaseAdmin admins = new HBaseAdmin(config);
TableName[] tables = admins.listTableNames();
for(TableName table: tables){
System.out.println(table.toString());
}
in Jdk 1.8, you need set
"System.setProperty("javax.security.auth.useSubjectCredsOnly", "false");"
config.set("hbase.zookeeper.quorum", zookeeperHosts);
config.set("hbase.zookeeper.property.clientPort", zookeeperPort);
config.set("hadoop.security.authentication", "kerberos");
config.set("hbase.security.authentication", "kerberos");
config.set("hbase.master.kerberos.principal", HBASE_MASTER_PRINCIPAL);
config.set("hbase.regionserver.kerberos.principal", HBASE_RS_PRINCIPAL);
System.setProperty("javax.security.auth.useSubjectCredsOnly", "false");
UserGroupInformation.setConfiguration(config);
UserGroupInformation.loginUserFromKeytab(ZOOKEEPER_PRINCIPAL,ZOOKEEPER_KEYTAB);
HBaseAdmin admins = new HBaseAdmin(config);
TableName[] tables = admins.listTableNames();
for(TableName table: tables){
System.out.println(table.toString());
}
quote:
http://hbase.apache.org/book.html#trouble.client
question: 142.9
I think the best is https://scalding.io/2015/02/making-your-hbase-client-work-in-a-kerberized-environment/
To make the code work you don’t have to change any line from the one written in the top of this post, you just have to make your client able to access the full HBase configuration. This just implies to change your running classpath to:
/opt/cloudera/parcels/CDH-5.3.0-1.cdh5.3.0.p0.30/lib/hbase/conf:target/scala-2.11/hbase-assembly-1.0.jar
This will make everything run smoothly. It is specific for CDH 5.3 but you can adapt it for your cluster configuration.
PS No need in this:
conf.addResource("core-site.xml");
conf.addResource("hbase-site.xml");
conf.addResource("hdfs-site.xml");
Because HBaseConfiguration has
public static Configuration addHbaseResources(Configuration conf) {
conf.addResource("hbase-default.xml");
conf.addResource("hbase-site.xml");

Categories