Integrate ActiveMQ with Wildfly 10 and Secure SSL Connection

In the previous post I have show how to configure JMS in Wildfly 10. But I have found the difficulty to secure SSL Communication by using Wildfly 10 default message broker. So, in this post I'll will show how to use ActiveMQ as message broker and integrate with Wildfly 10. I have found that ActiveMQ is easier to configure SSL than using build in message broker provided in Wildfly.

Install ActiveMQ

First, you need to download ActiveMQ from here. After downloading the package, archive the package.

Fig.01 download activemq
Next is to unzip the package.
$tar -xvf apache-activemq-5.15.11-bin.tar.gz
$mv apache-activemq-5.15.11 activemq
$cp -R activemq /opt/

Generate SSL keystore and truststore

You can use java keytool to create keystore and truststore for both broker and client. The concept is the same as you create keystore and truststore for HTTPS. You can refer in previous tutorial.

Fig.02 Creating Keystore and truststore concept.
First, you need to create keystore for broker and key store for client. Next is to export certificate for both broker and client. And finally, import certificates of client to broker's keystore and import broker's certification to each of client's truststore. you can refer as below.
## Create a keystore for the broker SERVER
keytool -genkey -alias broker -keyalg RSA -keysize 2048 -validity 35600 -storepass password -keypass password -dname "CN=wildfly.itstikk.pro, o=itstikk, c=LA" -keystore broker.keystore

## Export broker key certificate
keytool -export -alias broker -keystore broker.keystore -storepass password -file broker.cert

## Create a keystore/certificat for the client
keytool -genkey -alias client -keyalg RSA -keysize 2048 -validity 35600 -storepass password -keypass password -dname "CN=wildfly.itstikk.pro, o=itstikk, c=LA" -keystore client.keystore

## create truststore for the client, and import the broker's certificate
keytool -import -alias broker -keystore client.truststore -file broker.cert -storepass password -noprompt

## export client certificate
keytool -export -alias client -keystore client.keystore -storepass password -file client.cert

## import client certificate to broker's truststore
keytool -import -alias client -file client.cert -keystore broker.truststore -storepass password -noprompt
After execute this script you should get below keystore and truststore set as below.
-rw-rw-r-- 1 wildfly wildfly 799 Mar 29 11:57 broker.cert
-rw-rw-r-- 1 wildfly wildfly 2150 Mar 29 11:56 broker.keystore
-rw-rw-r-- 1 wildfly wildfly 862 Mar 29 11:58 broker.truststore
-rw-rw-r-- 1 wildfly wildfly 799 Mar 29 11:57 client.cert
-rw-rw-r-- 1 wildfly wildfly 2150 Mar 29 11:57 client.keystore
-rw-rw-r-- 1 wildfly wildfly 862 Mar 29 11:57 client.truststore
Maintain broker.keystore and broker truststore in the broker. And maintain client.keystore and client.truststore at the client side.

Setup SSL for ActiveMQ

To enable SSL for ActiveMQ, you need to edit activemq.xml as below

$vim /opt/activemq/conf/activemq.xml
add below to your activemq.xml
 <!--
            The managementContext is used to configure how ActiveMQ is exposed in
            JMX. By default, ActiveMQ uses the MBean server that is started by
            the JVM. For more information, see:
            http://activemq.apache.org/jmx.html
-->
<managementContext>
            <managementContext createConnector="false"/>
</managementContext>
<!-- SSL Connection -->
<sslContext>
    <sslContext keyStore="file:${ACTIVEMQ_KEYS}/broker.keystore"
        keyStorePassword="password" trustStore="file:${ACTIVEMQ_KEYS}/broker.truststore"
         trustStorePassword="password"/>
</sslContext>
And add below line to enable SSL
<!--
    The transport connectors expose ActiveMQ over a given protocol to
    clients and other brokers. For more information, see:

    http://activemq.apache.org/configuring-transports.html
-->
<transportConnectors>
    <!-- DOS protection, limit concurrent connections to 1000 and frame size to 100MB -->
    <transportConnector name="openwire" uri="tcp://0.0.0.0:61616?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
    <transportConnector name="ssl" uri="ssl://0.0.0.0:61714?transport.enabledProtocols=TLSv1.2"/>
    <!--
    <transportConnector name="amqp" uri="amqp://0.0.0.0:5672?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
    <transportConnector name="stomp" uri="stomp://0.0.0.0:61613?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
    <transportConnector name="mqtt" uri="mqtt://0.0.0.0:1883?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
    <transportConnector name="ws" uri="ws://0.0.0.0:61614?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
    -->
</transportConnectors>
now you can start activemq
$cd /opt/activemq/bin/linux-x86-64/
$ls -la
total 160
drwxrwxr-x 2 wildfly wildfly   4096 Mar 29 18:06 .
drwxrwxr-x 5 wildfly wildfly   4096 Feb 25 11:45 ..
-rwxr-xr-x 1 wildfly wildfly  15455 Nov 20 17:25 activemq
-rwxr-xr-x 1 wildfly wildfly  15248 Nov 20 16:34 libwrapper.so
-rwxr-xr-x 1 wildfly wildfly 111027 Nov 20 16:34 wrapper
-rw-r--r-- 1 wildfly wildfly   6033 Nov 20 17:25 wrapper.conf
$./activemq start
Now, check whether ActiveMQ run properly below
[wildfly@wildfly linux-x86-64]$ netstat -ntl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp         0           0        0.0.0.0:22                  0.0.0.0:*                     LISTEN
tcp         0           0        127.0.0.1:25              0.0.0.0:*                     LISTEN
tcp         0           0        127.0.0.1:32000        0.0.0.0:*                     LISTEN
tcp         0           0        0.0.0.0:111                0.0.0.0:*                     LISTEN
tcp         0           0        0.0.0.0:80                  0.0.0.0:*                     LISTEN
tcp6       0           0        :::61714                     :::*                             LISTEN
tcp6       0           0        :::22                           :::*                             LISTEN
tcp6       0           0        :::38152                     :::*                             LISTEN
tcp6       0           0        :::111                         :::*                             LISTEN
tcp6       0           0        :::61616                     :::*                             LISTEN

Configure Wildfly 10 and Set Up SSL for ActiveMQ connection

Now, we need to integrate Wildfly Application server with ActiveMQ. In order to that, we need to download resource adapter here. After finish download, copy activemq-rar-5.11.1.rar to Wildfly's deploy folder.
$cp activemq-rar-5.15.12.rar $JBOSS_HOME/standalone/deployments/
Next is to edit standalone-full.xml file.
<subsystem xmlns="urn:jboss:domain:resource-adapters:4.0">
    <resource-adapters>
        <resource-adapter id="activemq">
            <archive>
                activemq-rar-5.15.12.rar
            </archive>
            <transaction-support>XATransaction</transaction-support>
            <config-property name="ServerUrl">
                ssl://wildfly.itstikk.pro:61714
            </config-property>
            <config-property name="UserName">
                jms-user
            </config-property>
            <config-property name="UseInboundSession">
                false
            </config-property>
            <config-property name="Password">
                Qf48d8uv12!@
            </config-property>
<config-property name="TrustStore">
/opt/keys/activemq/client.truststore
</config-property>
<config-property name="TrustStorePassword">
password
</config-property>
<config-property name="KeyStore">
/opt/keys/activemq/client.keystore
</config-property>
<config-property name="KeyStorePassword">
password
</config-property>
            <connection-definitions>
                <connection-definition class-name="org.apache.activemq.ra.ActiveMQManagedConnectionFactory" jndi-name="java:/ConnectionFactory0" enabled="true" pool-name="ConnectionFactory">
                    <xa-pool>
                        <min-pool-size>1</min-pool-size>
                        <max-pool-size>20</max-pool-size>
                        <prefill>false</prefill>
                        <is-same-rm-override>false</is-same-rm-override>
                    </xa-pool>
<config-property name="TrustStore">
/opt/keys/activemq/client.truststore
</config-property>
<config-property name="TrustStorePassword">
password
</config-property>
<config-property name="KeyStore">
/opt/keys/activemq/client.keystore
</config-property>
<config-property name="KeyStorePassword">
password
</config-property>
                </connection-definition>
            </connection-definitions>
            <admin-objects>
                <admin-object class-name="org.apache.activemq.command.ActiveMQQueue" jndi-name="java:jboss/activemq/queue/TestQueue" use-java-context="true" pool-name="testQueue">
                    <config-property name="PhysicalName">
                        activemq/queue/TestQueue
                    </config-property>
                </admin-object>
            </admin-objects>
        </resource-adapter>
    </resource-adapters>
</subsystem>

And one more configuration

<subsystem xmlns="urn:jboss:domain:ejb3:4.0">
    <session-bean>
        <stateless>
            <bean-instance-pool-ref pool-name="slsb-strict-max-pool"/>
        </stateless>
        <stateful default-access-timeout="5000" cache-ref="simple" passivation-disabled-cache-ref="simple"/>
        <singleton default-access-timeout="5000"/>
    </session-bean>
    <mdb>
        <resource-adapter-ref resource-adapter-name="activemq"/>
        <bean-instance-pool-ref pool-name="mdb-strict-max-pool"/>
    </mdb>
    <pools>
        <bean-instance-pools>
            <strict-max-pool name="slsb-strict-max-pool" derive-size="from-worker-pools" instance-acquisition-timeout="5" instance-acquisition-timeout-unit="MINUTES"/>
            <strict-max-pool name="mdb-strict-max-pool" derive-size="from-cpu-count" instance-acquisition-timeout="5" instance-acquisition-timeout-unit="MINUTES"/>
        </bean-instance-pools>
    </pools>
    <caches>
        <cache name="simple"/>
        <cache name="distributable" passivation-store-ref="infinispan" aliases="passivating clustered"/>
    </caches>
    <passivation-stores>
        <passivation-store name="infinispan" cache-container="ejb" max-size="10000"/>
    </passivation-stores>
    <async thread-pool-name="default"/>
    <timer-service thread-pool-name="default" default-data-store="default-file-store">
        <data-stores>
            <file-data-store name="default-file-store" path="timer-service-data" relative-to="jboss.server.data.dir"/>
        </data-stores>
    </timer-service>
    <remote connector-ref="http-remoting-connector" thread-pool-name="default"/>
    <thread-pools>
        <thread-pool name="default">
            <max-threads count="10"/>
            <keepalive-time time="100" unit="milliseconds"/>
        </thread-pool>
    </thread-pools>
    <iiop enable-by-default="false" use-qualified-name="false"/>
    <default-security-domain value="other"/>
    <default-missing-method-permissions-deny-access value="true"/>
    <log-system-exceptions value="true"/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:io:1.1">
    <worker name="default"/>
    <buffer-pool name="default"/>
</subsystem>

Now start Wildfly.
$cd $JBOSS_HOME/bin
$bash standalone.sh -c=standalone-full.xml

After start Wildfly, if you configuration is working you could see the queue is created in the message broker.
Fig.03 check the queue is created

Create Message Producer and Message Consumer to test the set up

First you need to create message producer by creating JAVA SE project and create Java Class.
package pro.itstikk.jms.app;

import java.io.File;

import javax.jms.Connection;
import javax.jms.Destination;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.apache.activemq.ActiveMQSslConnectionFactory;

public class Main01 {
private static final String CLIENT_TS_FILE="E:\\workplace\\keys\\activemq\\keys\\client.truststore";
private static final String CLIENT_KS_FILE="E:\\workplace\\keys\\activemq\\keys\\client.keystore";

        private static String url = "ssl://wildfly.itstikk.pro:61714";
        private static String subject = "activemq/queue/TestQueue"; // Queue Name.You can create any/many queue names as per your requirement. 

        public static void main(String[] args) throws Exception {
// Getting JMS connection from the server and starting it
ActiveMQSslConnectionFactory connectionFactory = new ActiveMQSslConnectionFactory(url);
connectionFactory.setUserName("jms-user");
connectionFactory.setPassword("Qf48d8uv12!@");
connectionFactory.setTrustStore(new File(CLIENT_TS_FILE).toURI().toString());
connectionFactory.setTrustStorePassword("password");
connectionFactory.setKeyStore(new File(CLIENT_KS_FILE).toURI().toString());
connectionFactory.setKeyStorePassword("password");
Connection connection = connectionFactory.createConnection();
connection.start();
       
         
        //Creating a non transactional session to send/receive JMS message.
        Session session = connection.createSession(false,
                Session.AUTO_ACKNOWLEDGE);  
         
        //Destination represents here our queue 'JCG_QUEUE' on the JMS server. 
        //The queue will be created automatically on the server.
        Destination destination = session.createQueue(subject); 
         
        // MessageProducer is used for sending messages to the queue.
        MessageProducer producer = session.createProducer(destination);
         
        // We will send a small text message saying 'Hello World!!!' 
        TextMessage message = session
                .createTextMessage("Hello !!! Welcome to the world of ActiveMQ.");
         
        // Here we are sending our message!
        for(int i=0;i<10000;i++) {
        System.out.println("send message to the queue !!!!!!!!!!!");
        producer.send(message);
        }
         
        System.out.println("JCG printing@@ '" + message.getText() + "'");
        connection.close();

}


}

Next is to create EJB Project and Message Driven Bean Class, package in your EAR file and deploy to the application server.
package pro.itstikk.wildfly;

import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

/**
 * Message-Driven Bean implementation class for: ActiveMQMDB
 */
@MessageDriven(activationConfig = {
 
        @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),

        @ActivationConfigProperty(propertyName = "destination", propertyValue = "activemq/queue/TestQueue") })
public class ActiveMQMDB implements MessageListener {

    /**
     * Default constructor. 
     */
    public ActiveMQMDB() {
        super();
    }

/**
     * @see MessageListener#onMessage(Message)
     */
    public void onMessage(Message message) {
    try {
     
            if (message instanceof TextMessage) {

                System.out.println(">>>> Got Message "

                        + ((TextMessage) message).getText());

            }

        } catch (JMSException e) {

            e.printStackTrace();

        }

    }

}

Reference


No comments:

Post a Comment

Feature Recently

Running Wildfly Application Server in Domain Mode

  Wildfly application server provides two modes of how to run application one wildfly application server. It is very simple if you run your ...

Most Views