May 28, 2017

Roadmap Apache ActiveMQ, HornetQ and Apache ActiveMQ Artemis

HornetQ was the built in Message Broker in JBoss EAP 6.

Red Hat bought FuseSource in 2012, the company behind ActiveMQ commercial support, and rebranded the product JBoss A-MQ server. This left Red Hat with two competing Message Brokers.

In 2014 Red Hat and the HornetQ community decided to join efforts with the ActiveMQ community and the Apache ActiveMQ Artemis was created.

The current Red Hat JBoss A-MQ releases, at the time of 7.0.0, was still based on the original ActiveMQ project. It is expected a future release will be based on the Artemis project. This future release will feature the external appearance of the current A-MQ product (administration interfaces based on Fabric, protocol supported, and native client libraries) but with many of the internals from HornetQ (asynchronous I/O engine and high performance journaled disk storage).

The JBoss EAP 7 is shipped with the Apache ActiveMQ Artemis.

May 18, 2017

NamingException in RPM Installed Tomcat 7 in RHEL 7 and CentoIOS 7

If you are using datasource in rpm installed tomcat 7 on RHEL 7 and CentOS and do not specify factory, you will get a NamingException.

For details see https://bugzilla.redhat.com/show_bug.cgi?id=819087.

<Context>

    ...
    <Resource name="jdbc/ReviewDb" auth="Container" type="javax.sql.DataSource"
              factory="org.apache.commons.dbcp.BasicDataSourceFactory"
              driverClassName="org.postgresql.Driver"
              url="jdbc:postgresql://dbhost:5432/reviewdb"
              username="gerrit2" password="******" maxActive="20"
              maxIdle="10" maxWait="-1"/>
</Context>
javax.naming.NamingException: Could not create resource factory instance [Root exception is java.lang.ClassNotFoundException: org.apache.tomcat.dbcp.dbcp.BasicDataSourc
eFactory]
        at org.apache.naming.factory.ResourceFactory.getObjectInstance(ResourceFactory.java:119)
        at javax.naming.spi.NamingManager.getObjectInstance(NamingManager.java:321)
        at org.apache.naming.NamingContext.lookup(NamingContext.java:842)
        at org.apache.naming.NamingContext.lookup(NamingContext.java:153)
        at org.apache.naming.NamingContextBindingsEnumeration.nextElementInternal(NamingContextBindingsEnumeration.java:117)
        at org.apache.naming.NamingContextBindingsEnumeration.next(NamingContextBindingsEnumeration.java:71)
        at org.apache.naming.NamingContextBindingsEnumeration.next(NamingContextBindingsEnumeration.java:34)
        at org.apache.catalina.mbeans.GlobalResourcesLifecycleListener.createMBeans(GlobalResourcesLifecycleListener.java:138)
        at org.apache.catalina.mbeans.GlobalResourcesLifecycleListener.createMBeans(GlobalResourcesLifecycleListener.java:110)
        at org.apache.catalina.mbeans.GlobalResourcesLifecycleListener.lifecycleEvent(GlobalResourcesLifecycleListener.java:82)
        at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
        at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:90)
        at org.apache.catalina.util.LifecycleBase.setStateInternal(LifecycleBase.java:402)
        at org.apache.catalina.util.LifecycleBase.setState(LifecycleBase.java:347)
        at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:724)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
        at org.apache.catalina.startup.Catalina.start(Catalina.java:689)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:497)
        at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:321)
        at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:455)
Caused by: java.lang.ClassNotFoundException: org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory
        at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:264)
        at org.apache.naming.factory.ResourceFactory.getObjectInstance(ResourceFactory.java:115)
        ... 22 more

How to Generate Elliptic Curve Keys in Java 8

// Supported Providers in Java 8
for (Provider provider : Security.getProviders()) {
    System.out.println("Provider : " + provider);
}

// Supported Algorithm in Java: "DiffieHellman", "DSA", "RSA" and "EC"
// https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyPairGenerator

KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC", "SunEC");
// SecureRandom.getInstanceStrong() (Java 8) is the Recommended way to use initialize random,
// it chooses automatically the strongest algorithm for your OS
keyGen.initialize(256, SecureRandom.getInstanceStrong());
KeyPair kp = keyGen.genKeyPair();
PrivateKey privateKey = kp.getPrivate();
PublicKey publicKey = kp.getPublic();
System.out.println("PrivateKey : " + privateKey);
System.out.println("PublicKey : " + publicKey);
// the key in its primary encoding format
byte[] publicKeyInfo = publicKey.getEncoded();
c

How to RPM Install JBoss EAP 7 on RHEL 7

First you need to add JBoss EAP 7 subscription. To do that you need the pool id for your subscription. To find that out list all available subscription and then look for JBoss subscription.

# subscription-manager list --available --all > /tmp/subscription.txt
# less /tmp/subscription.txt
Subscription Name:   JBoss ....
Provides:            Red Hat OpenShift Enterprise JBoss EAP add-on Beta
                     Red Hat JBoss A-MQ Clients
                     Red Hat Single Sign-On
                     Red Hat OpenShift Enterprise JBoss EAP add-on
                     JBoss Enterprise Application Platform
                     Red Hat JBoss Core Services
                     Red Hat JBoss Data Grid
                     JBoss Enterprise Web Server
                     Red Hat JBoss A-MQ Interconnect
...
Pool ID:             XXXXXXXXXXXXXX
...

Now add that subscription with above pool id.

# subscription-manager attach --pool=XXXXXXXXXXXXXX

Then you need to enable the JBoss EAP 7 repo. There are multiple repos. Here we wil run JBoss EAP 7 on RHEL 7 and for that there are two repos:

  • Current JBoss EAP 7 Repository (repo id: jb-eap-7-for-rhel-7-server-rpms)
  • Recommended. Always use the latest.

  • Minor JBoss EAP 7 Repository (repo id: jb-eap-7.[MINOR_VERSION]-for-rhel-7-server-rpms, where MINOR_VERSION is the wanted lock down version, i.e. 0)
  • Only use a specific minor version and never upgrade to next minor, e.g. 7.1, 7.2, etc.

So to use the latest version enable repo by

# subscription-manager repos --enable=jb-eap-7-for-rhel-7-server-rpms

Finally verify that JBoss EAP 7 repo had been enabled with yum.

# yum repolist
repo id                                                                                            repo name
jb-eap-7-for-rhel-7-server-rpms/7Server/x86_64                                                     JBoss Enterprise Application Platform 7 (RHEL 7 Server) (RPMs)
rhel-7-server-rpms/7Server/x86_64                                                                  Red Hat Enterprise Linux 7 Server (RPMs)

Now we install JBoss EAP 7 as a RPM group. To list all

# yum grouplist
Available Environment Groups:
   Minimal Install
...
Available Groups:
...
   JBoss EAP 7
...

And to also list hidden groups.

# yum grouplist hidden

Before you install JBoss EAP 7, you want to install java (JRE) in a controlled way, so it is not transative installed.

# yum install java-1.8.0-openjdk

Then install JBoss EAP 7 RPM group

# yum groupinstall "JBoss EAP 7"

Finally auto start jboss on reboot

# systemctl enable eap7-standalone

And then start it

# systemctl enable eap7-standalone

JBoss EAP 7 binds default to any network interface.

# netstat -tulnp | grep 8080
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      2210/java           

And if this is a remote machine, you need to open port 8080 in local firewall.

# firewall-cmd --add-port 8080/tcp --zone public --permanent
# firewall-cmd --reload
# firewall-cmd --list-all-zones

JBOSS_HOME: /opt/rh/eap7/root/usr/share/wildfly/

A note about jboss home long path. This is due to docker and to be able to ship different software version on same machine, then you cannot install software in default directory, i.e. jboss default directory is /usr/share/wildfly/. To read more, please see Red Hat Software Collections (RHSCL).

# ll /opt/rh/eap7/root/usr/share/wildfly/
total 40
drwxrwxr-x. 2 root root    27 17 maj 21.59 appclient
drwxr-xr-x. 3 root root  4096 17 maj 21.59 bin
drwxrwxr-x. 2 root root    52 17 maj 21.59 docs
drwxr-xr-x. 2 root root    76 17 maj 21.59 domain
-rw-rw-r--. 1 root root   419 21 feb 10.15 JBossEULA.txt
lrwxrwxrwx. 1 root root    50 17 maj 21.59 jboss-modules.jar -> /opt/rh/eap7/root/usr/share/java/jboss-modules.jar
-rw-rw-r--. 1 root root 26530 21 feb 10.15 LICENSE.txt
drwxrwxr-x. 3 root root    20 17 maj 21.59 modules
drwxr-xr-x. 2 root root    91 17 maj 21.59 standalone
-rw-rw-r--. 1 root root    65 21 feb 10.15 version.txt
drwxrwxr-x. 4 root root   158 17 maj 21.59 welcome-content
# ll /opt/rh/eap7/root/usr/share/wildfly/standalone/
total 0
lrwxrwxrwx. 1 root root 35 17 maj 21.59 configuration -> /etc/opt/rh/eap7/wildfly/standalone
lrwxrwxrwx. 1 root root 44 17 maj 21.59 data -> /var/opt/rh/eap7/lib/wildfly/standalone/data
lrwxrwxrwx. 1 root root 51 17 maj 21.59 deployments -> /var/opt/rh/eap7/lib/wildfly/standalone/deployments
lrwxrwxrwx. 1 root root 43 17 maj 21.59 lib -> /var/opt/rh/eap7/lib/wildfly/standalone/lib
lrwxrwxrwx. 1 root root 39 17 maj 21.59 log -> /var/opt/rh/eap7/log/wildfly/standalone
lrwxrwxrwx. 1 root root 45 17 maj 21.59 tmp -> /var/opt/rh/eap7/cache/wildfly/standalone/tmp

May 15, 2017

Configure Java KeyStore and TrustStore

KeyStore

javax.net.ssl.keyStore
javax.net.ssl.keyStorePassword
javax.net.ssl.keyStoreType Typical [JKS|PKCS12]

And how to use it.

$ java -Djavax.net.ssl.keyStore=/path/to/file -Djavax.net.ssl.keyStorePassword=changeit -Djavax.net.ssl.keyStoreType=JKS

TrustStore

javax.net.ssl.trustStore
javax.net.ssl.trustStorePassword
javax.net.ssl.trustStoreType Typical [JKS|PKCS12]

Miscellaneous

javax.net.debug [ssl|debug|all]
jdk.tls.client.protocols E.g. TLSv1,TLSv1.1

Reference: Java Secure Socket Extension (JSSE) Reference Guide Customizing JSSE

May 14, 2017

Tomcat Standard Security Realms

Tomcat comes out of the box with the following security realms, i.e. modules that does Authentication and Authorization.

Name CIS Tomcat 8 Benchmark Note *
JDBCRealm NOT for Production
DataSourceRealm  
JNDIRealm (LDAP)  
UserDatabaseRealm NOT for Large-Scale Installations
MemoryRealm NOT for Production
JAASRealm NOT widely used and therefore the code is not as mature as the other realms.

*) CIS_Apache_Tomcat_8_Benchmark_v1.0.1.pdf

This leaves us with only two production ready realms: DataSourceRealm and JNDIRealm (LDAP)

There are two other Realms (CombinedRealm and LockOutRealm), but they do not do authentication and authorization.

How to handle Configuration in Tomcat with Context

Background

In Tomcat there seems no way to handle war deployment with version number in file name.

"When autoDeploy or deployOnStartup operations are performed by a Host, the name and context path of the web application are derived from the name(s) of the file(s) that define(s) the web application. Consequently, the context path may not be defined in a META-INF/context.xml embedded in the application and there is a close relationship between the context name, context path, context version and the base file name (the name minus any .war or .xml extension) of the file." [https://tomcat.apache.org/tomcat-8.0-doc/config/context.html]

So in your maven pom, you need to set <build><finalName>${project.artifactId}</finalName>...</build>.

Context Configuration

The context.xml can be placed:

  • $CATALINA_BASE/conf/[enginename]/[hostname]/[your_war_file_name].xml, e.g. $CATALINA_BASE/Catalina/localhost/example-tomcat.xml. Only visible inside example-tomcat.war.
  • $CATALINA_BASE/conf/context.xml. Global visible.
  • [your_war_file]/META-INF/context.xml. Deployed in your war file. This is not suited for configurable values.

The only sensible alternative of the above is the first. This is also good for RPM, since each application have a separate configuration file and no file collision from different RPM.

A little note about the path $CATALINA_BASE/conf/[enginename]/[hostname]/. If you look at your $CATALINA_BASE/conf/server.xml file, you see where [enginename] and [hostname] come from.

<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">

    ...
    <Service name="Catalina">

        ...
        <Engine name="Catalina" defaultHost="localhost">

            <Host name="localhost" appBase="webapps" unpackWARs="true"
                autoDeploy="true">

                ...
            </Host>
        </Engine>
    </Service>
</Server>

More Configuration in Context

You can also put general configuration in you Context.

 <Context>
      ...
     <Parameter name="companyName" value="My Company, Incorporated"
          override="false"/>
       ...
 </Context>

   This is equivalent to the inclusion of the following element in the web application deployment descriptor (/WEB-INF/web.xml):

 <context-param>
       <param-name>companyName</param-name>
       <param-value>My Company, Incorporated</param-value>
 </context-param>

And retrieve it by

ServletContext sc = getServletContext();  
String companyName = sc.getInitParameter("companyName");