jms

Apache ActiveMQ SSL Example

1. Introduction

Secure Sockets Layer (SSL) is a standard security protocol for establishing encrypted links between a web server and a browser in an online communication. SSL was originally developed for securing web browser and server communications by Netscape in 1994. Subsequently, the protocol was adopted by the Internet Engineering Task Force (IETF) and renamed to Transport Layer Security (TLS) under RFC 2246 in 1999. SSL/TLS addresses the following security considerations:

  • Authentication: During SSL Handshake process, the server and client make sure the computer speaking to is trusted
  • Confidentiality: The data that is passed between the client and server is encrypted
  • Integrity: The data that is passed between the client and server cannot be modified

 
Java Security Socket Extension (JSSE) is the Java implementation of SSL/TLS protocols. It includes functionality for data encryption, sever authentication, message integrity, and optional client-authentication.

Apache ActiveMQ (AMQ) is written in Java and implements JMS 1.1 specification from the Apache Software Foundation. ActiveMQ uses JSSE to support SSL.

Assuming you understand both AMQ and SSL. In this example, I will demonstrate how to configure an AMQ broker to support SSL and how to create a simple Java application which connects to it securely.

2. Technologies Used

The example code in this article was built and run using:

  • Java 1.8.101 (1.8.x will do fine)
  • Maven 3.3.9 (3.3.x will do fine)
  • Apache ActiveMQ 5.15.3 (others will do fine)
  • Eclipse Mars (Any Java IDE would work)

3. Configure ActiveMQ Server

In this step, we will configure an AMQ server to support the SSL transport in three steps:

  1. Install an AMQ server.
  2. Alter the configuration file to support SSL.
  3. Start the AMQ server and verify the SSL connector is started.

3.1 Activemq.xml

Install AMQ 5.15.3 at a Windows PC. Please check out my other article for more details. If you want to generate a new security key, please follow this article to do so.

In this step, we will use the security certificate that came with the installation and update activemq.xml to enable the SSL transport connector.

activemq.xml

<!--
    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
    this work for additional information regarding copyright ownership.
    The ASF licenses this file to You under the Apache License, Version 2.0
    (the "License"); you may not use this file except in compliance with
    the License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
-->
<!-- START SNIPPET: example -->
<beans
  xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core.xsd">

    <!-- Allows us to use system properties as variables in this configuration file -->
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <value>file:${activemq.conf}/credentials.properties</value>
        </property>
    </bean>

   <!-- Allows accessing the server log -->
    <bean id="logQuery" class="io.fabric8.insight.log.log4j.Log4jLogQuery"
          lazy-init="false" scope="singleton"
          init-method="start" destroy-method="stop">
    </bean>

    <!--
        The <broker> element is used to configure the ActiveMQ broker.
    -->
    <broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost" dataDirectory="${activemq.data}">

        <destinationPolicy>
            <policyMap>
              <policyEntries>
                <policyEntry topic=">" >
                    <!-- The constantPendingMessageLimitStrategy is used to prevent
                         slow topic consumers to block producers and affect other consumers
                         by limiting the number of messages that are retained
                         For more information, see:

                         http://activemq.apache.org/slow-consumer-handling.html

                    -->
                  <pendingMessageLimitStrategy>
                    <constantPendingMessageLimitStrategy limit="1000"/>
                  </pendingMessageLimitStrategy>
                </policyEntry>
              </policyEntries>
            </policyMap>
        </destinationPolicy>


        <!--
            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>
		<sslContext> 
            <sslContext keyStore="file:${activemq.base}/conf/broker.ks" 
              keyStorePassword="password" trustStore="file:${activemq.base}/conf/broker.ts" 
              trustStorePassword="password"/> 
        </sslContext> 


        <!--
            Configure message persistence for the broker. The default persistence
            mechanism is the KahaDB store (identified by the kahaDB tag).
            For more information, see:

            http://activemq.apache.org/persistence.html
        -->
        <persistenceAdapter>
            <kahaDB directory="${activemq.data}/kahadb"/>
        </persistenceAdapter>


          <!--
            The systemUsage controls the maximum amount of space the broker will
            use before disabling caching and/or slowing down producers. For more information, see:
            http://activemq.apache.org/producer-flow-control.html
          -->
          <systemUsage>
            <systemUsage>
                <memoryUsage>
                    <memoryUsage percentOfJvmHeap="70" />
                </memoryUsage>
                <storeUsage>
                    <storeUsage limit="100 gb"/>
                </storeUsage>
                <tempUsage>
                    <tempUsage limit="50 gb"/>
                </tempUsage>
            </systemUsage>
        </systemUsage>

        <!--
            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="amqp" uri="amqp://0.0.0.0:5672?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
            <transportConnector name="stomp" uri="stomp://0.0.0.0:61613?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
            <transportConnector name="mqtt" uri="mqtt://0.0.0.0:1883?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
            <transportConnector name="ws" uri="ws://0.0.0.0:61614?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/> 
			 -->
			
			 <transportConnector name="openwire" uri="tcp://0.0.0.0:61616?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
			 <transportConnector name="ssl" uri="ssl://0.0.0.0:61714?transport.enabledProtocols=TLSv1.2"/>
			 
        </transportConnectors>

        <!-- destroy the spring context on shutdown to stop jetty -->
        <shutdownHooks>
            <bean xmlns="http://www.springframework.org/schema/beans" class="org.apache.activemq.hooks.SpringContextHook" />
        </shutdownHooks>

    </broker>

    <!--
        Enable web consoles, REST and Ajax APIs and demos
        The web consoles requires by default login, you can disable this in the jetty.xml file

        Take a look at ${ACTIVEMQ_HOME}/conf/jetty.xml for more details
    -->
    <import resource="jetty.xml"/>

</beans>
<!-- END SNIPPET: example -->
  • line 73-77: Specify the AMQ server keystore properties
  • line 126-127: Enable the SSL transport with TLS protocol

3.2 Server log

Start the AMQ server.

server.log

wrapper  | --> Wrapper Started as Console
wrapper  | Launching a JVM...
jvm 1    | Wrapper (Version 3.2.3) http://wrapper.tanukisoftware.org
jvm 1    |   Copyright 1999-2006 Tanuki Software, Inc.  All Rights Reserved.
jvm 1    |
jvm 1    | Java Runtime: Oracle Corporation 1.8.0_40 C:\Program Files\Java\jre1.8.0_40
jvm 1    |   Heap sizes: current=251392k  free=235655k  max=932352k
jvm 1    |     JVM args: -Dactivemq.home=../.. -Dactivemq.base=../.. -Djavax.net.ssl.keyStorePassword=password -javax.net.ssl.trustStorePassword=password -Djavax.net.ssl.keyStore=../../conf/broker.ks -Djavax.net.ssl.trustStore=../../conf/broker.ts -Dcom.sun.management.jmxremote -Dorg.apache.activemq.UseDedicatedTaskRunner=true -Djava.util.logging.config.file=logging.properties -Dactivemq.conf=../../conf -Dactivemq.data=../../data -Djava.security.auth.login.config=../../conf/login.config -Xmx1024m -Djava.library.path=../../bin/win64 -Dwrapper.key=V4xc5qXB92bkkPap -Dwrapper.port=32000 -Dwrapper.jvm.port.min=31000 -Dwrapper.jvm.port.max=31999 -Dwrapper.pid=19168 -Dwrapper.version=3.2.3 -Dwrapper.native_library=wrapper -Dwrapper.cpu.timeout=10 -Dwrapper.jvmid=1
jvm 1    | Extensions classpath:
jvm 1    |   [..\..\lib,..\..\lib\camel,..\..\lib\optional,..\..\lib\web,..\..\lib\extra]
jvm 1    | ACTIVEMQ_HOME: ..\..
jvm 1    | ACTIVEMQ_BASE: ..\..
jvm 1    | ACTIVEMQ_CONF: ..\..\conf
jvm 1    | ACTIVEMQ_DATA: ..\..\data
jvm 1    | Loading message broker from: xbean:activemq.xml
jvm 1    |  INFO | Refreshing org.apache.activemq.xbean.XBeanBrokerFactory$1@244a02d0: startup date [Mon May 14 19:42:09 CDT 2018]; root of context hierarchy
jvm 1    |  INFO | Using Persistence Adapter: KahaDBPersistenceAdapter[C:\MaryZheng\tools\apache-activemq-5.15.3\bin\win64\..\..\data\kahadb]
jvm 1    |  INFO | KahaDB is version 6
jvm 1    |  INFO | PListStore:[C:\MaryZheng\tools\apache-activemq-5.15.3\bin\win64\..\..\data\localhost\tmp_storage] started
jvm 1    |  INFO | Apache ActiveMQ 5.15.3 (localhost, ID:SL2LS431841-55107-1526344932236-0:1) is starting
jvm 1    |  INFO | Listening for connections at: tcp://SL2LS431841:61616?maximumConnections=1000&wireFormat.maxFrameSize=104857600
jvm 1    |  INFO | Connector openwire started
jvm 1    |  INFO | Listening for connections at: ssl://SL2LS431841:61714?transport.enabledProtocols=TLSv1.2
jvm 1    |  INFO | Connector ssl started
jvm 1    |  INFO | Apache ActiveMQ 5.15.3 (localhost, ID:SL2LS431841-55107-1526344932236-0:1) started
jvm 1    |  INFO | For help or more information please see: http://activemq.apache.org
jvm 1    |  WARN | Store limit is 102400 mb (current store usage is 3 mb). The data directory: C:\MaryZheng\tools\apache-activemq-5.15.3\bin\win64\..\..\data\kahadb only has 58614 mb of usable space. - resetting to maximum available disk space: 58614 mb
jvm 1    |  INFO | No Spring WebApplicationInitializer types detected on classpath
jvm 1    |  INFO | ActiveMQ WebConsole available at http://0.0.0.0:8161/
jvm 1    |  INFO | ActiveMQ Jolokia REST API available at http://0.0.0.0:8161/api/jolokia/
jvm 1    |  INFO | Initializing Spring FrameworkServlet 'dispatcher'
jvm 1    |  INFO | No Spring WebApplicationInitializer types detected on classpath
jvm 1    |  INFO | jolokia-agent: Using policy access restrictor classpath:/jolokia-access.xml

Note:

  • line 8: Pay attention to the JVM options for the security properties
  • line 21: AMQ server starts the tcp connector at port 61616
  • line 23-24: AMQ server starts the ssl connector at port 61714

3.3 AMQ Management Console

We can verify the AMQ server’s ssl connector via the AMQ management web console. Go to http://localhost:8161/admin/connections.jsp and confirm the ssl connector.

Figure 1, AMQ connection

4. Connect to ActiveMQ Server

In this step, we will build two Java applications:

  • QueueMessageConsumer – connects to an AMQ server at an open wire port and consumes the messages
  • QueueMessageProducer – connects to an AMQ server at a secured port and publishes the messages

4.1 Publish Messages via a Secured Port

Imagine a customer sends sensitive data to your AMQ server, we need to secure the data by enabling the SSL connection. In this step, we will build a QueueMessageProducer class to publish the messages into a queue via a secured connection.

QueueMessageProducer.java

package jcg.demo.activemq.ssl;

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

import org.apache.activemq.ActiveMQSslConnectionFactory;

/**
 * A simple message producer which sends the message to ActiveMQ Broker
 * 
 * @author Mary.Zheng
 *
 */
public class QueueMessageProducer {

	private String activeMqBrokerUri;
	private String username;
	private String password;

	public static void main(String[] args) {
		QueueMessageProducer queProducer = new QueueMessageProducer("ssl://localhost:61714", "admin", "admin");
		queProducer.sendDummyMessages("test.queue");

	}

	public QueueMessageProducer(String activeMqBrokerUri, String username, String password) {
		super();
		this.activeMqBrokerUri = activeMqBrokerUri;
		this.username = username;
		this.password = password;
	}

	public void sendDummyMessages(String queueName) {
		System.out.println("QueueMessageProducer started " + this.activeMqBrokerUri);
		ActiveMQSslConnectionFactory connFactory = null;
		Connection connection = null;
		Session session = null;
		MessageProducer msgProducer = null;
		try {
			connFactory = new ActiveMQSslConnectionFactory(activeMqBrokerUri);
			connFactory.setUserName(username);
			connFactory.setPassword(password);
			connection = connFactory.createConnection();

			connection.start();
			session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
			msgProducer = session.createProducer(session.createQueue(queueName));

			for (int i = 0; i < 10; i++) {
				TextMessage textMessage = session.createTextMessage(buildDummyMessage(i));
				msgProducer.send(textMessage);
				try {
					Thread.sleep(10000);
				} catch (InterruptedException e) {
				}
			}
			System.out.println("QueueMessageProducer completed");
		} catch (JMSException e) {
			e.printStackTrace();
			System.out.println("Caught exception: " + e.getMessage());
		} catch (Exception e1) {
			System.out.println("Caught exception: " + e1.getMessage());
		}
		try {
			if (msgProducer != null) {
				msgProducer.close();
			}
			if (session != null) {
				session.close();
			}
			if (connection != null) {
				connection.close();
			}
		} catch (Throwable ignore) {
		}
	}

	private String buildDummyMessage(int value) {
		return "dummy message " + value;
	}
}
  • line 24: Pay attention to the ssl connection

4.2 Consume Messages via a Non-Secured Port

Once the data is in the AMQ server, internal processes, which are protected by the IT firewall, can consume these messages via a non-secured connector for better performance. In this step, we will build a QueueMessageConsumer class to consume the messages from a queue via a non-secured connection.

QueueMessageConsumer.java

package jcg.demo.activemq.ssl;

import javax.jms.Connection;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.apache.activemq.ActiveMQConnectionFactory;

/**
 * A simple message consumer which consumes the message from ActiveMQ Broker
 * 
 * @author Mary.Zheng
 *
 */
public class QueueMessageConsumer implements MessageListener {

	private String activeMqBrokerUri;
	private String username;
	private String password;
	private String destinationName;

	public static void main(String[] args) {

		QueueMessageConsumer queueMsgListener = new QueueMessageConsumer("tcp://localhost:61616", "admin", "admin");
		queueMsgListener.setDestinationName("test.queue");

		try {
			queueMsgListener.run();
		} catch (JMSException e) {
			e.printStackTrace();
		}
	}

	public QueueMessageConsumer(String activeMqBrokerUri, String username, String password) {
		super();
		this.activeMqBrokerUri = activeMqBrokerUri;
		this.username = username;
		this.password = password;
	}

	public void run() throws JMSException {
		ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(username, password, activeMqBrokerUri);
		Connection connection = factory.createConnection();
		connection.setClientID("MaryClient");
		connection.start();
		Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
		Destination destination = session.createQueue(destinationName);
		MessageConsumer consumer = session.createConsumer(destination);
		consumer.setMessageListener(this);

		System.out.println(String.format("QueueMessageConsumer Waiting for messages at %s %s", destinationName,
				this.activeMqBrokerUri));
	}

	@Override
	public void onMessage(Message message) {
		String msg;
		try {
			msg = String.format("QueueMessageConsumer Received message [ %s ]", ((TextMessage) message).getText());
			Thread.sleep(10000);// sleep for 10 seconds
			System.out.println(msg);
		} catch (JMSException | InterruptedException e) {
			e.printStackTrace();
		}
	}

	public String getDestinationName() {
		return destinationName;
	}

	public void setDestinationName(String destinationName) {
		this.destinationName = destinationName;
	}
}
  • line 29: Pay attention to the open wire connection

4.3 Install Security Certificate

The client needs to install the security certificate to establish the secured connection. There are several ways to get the security certificate installed for a Java program. As a Java developer, I use the InstallCert class to do so. The source code is credited to Andreas Sterbenz.

InstallCert.java

/*
 * Copyright 2006 Sun Microsystems, Inc.  All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   - Neither the name of Sun Microsystems nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
/**
 * Originally from:
 * http://blogs.sun.com/andreas/resource/InstallCert.java
 * Use:
 * java InstallCert hostname
 * Example:
 *% java InstallCert ecc.fedora.redhat.com
 */

package jcg.demo.activemq.ssl.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

public class InstallCert {

	public static void main(final String[] args) {
		InstallCert installCert = new InstallCert();

		try {
			installCert.generateCert("localhost", 61714);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void generateCert(String host, int port) throws Exception {

		File file = getJsSecCertsFile();

		System.out.println("Loading KeyStore " + file + "...");
		final InputStream in = new FileInputStream(file);
		final KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
		ks.load(in, passphrase);
		in.close();

		final SSLContext context = SSLContext.getInstance("TLS");
		final TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
		tmf.init(ks);
		final X509TrustManager defaultTrustManager = (X509TrustManager) tmf.getTrustManagers()[0];
		final SavingTrustManager tm = new SavingTrustManager(defaultTrustManager);
		context.init(null, new TrustManager[] { tm }, null);
		final SSLSocketFactory factory = context.getSocketFactory();

		System.out.println("Opening connection to " + host + ":" + port + "...");
		final SSLSocket socket = (SSLSocket) factory.createSocket(host, port);
		socket.setSoTimeout(10000);
		try {
			System.out.println("Starting SSL handshake...");
			socket.startHandshake();
			socket.close();
			System.out.println();
			System.out.println("No errors, certificate is already trusted");
		} catch (final SSLException e) {
			System.out.println();
			e.printStackTrace(System.out);
		}

		final X509Certificate[] chain = tm.chain;
		if (chain == null) {
			System.out.println("Could not obtain server certificate chain");
			return;
		}

		final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

		System.out.println();
		System.out.println("Server sent " + chain.length + " certificate(s):");
		System.out.println();
		final MessageDigest sha1 = MessageDigest.getInstance("SHA1");
		final MessageDigest md5 = MessageDigest.getInstance("MD5");
		for (int i = 0; i > 4]);
			sb.append(HEXDIGITS[b & 15]);
			sb.append(' ');
		}
		return sb.toString();
	}

	private static class SavingTrustManager implements X509TrustManager {

		private final X509TrustManager tm;
		private X509Certificate[] chain;

		SavingTrustManager(final X509TrustManager tm) {
			this.tm = tm;
		}

		@Override
		public X509Certificate[] getAcceptedIssuers() {
			return new X509Certificate[0];
		}

		@Override
		public void checkClientTrusted(final X509Certificate[] chain, final String authType)
				throws CertificateException {
			throw new UnsupportedOperationException();
		}

		@Override
		public void checkServerTrusted(final X509Certificate[] chain, final String authType)
				throws CertificateException {
			this.chain = chain;
			this.tm.checkServerTrusted(chain, authType);
		}
	}
}
  • line 68: AMQ starts the SSL connector at port 61714. Client installs its certificate.

5. Demo

First, execute the InstallCert to install the certificate into Java keystore. You can try running the program twice to confirm that the certificate is installed correctly.

InstallCert output

Loading KeyStore C:\MaryZheng\tools\java\jdk1.8.0_31\jre\lib\security\cacerts...
Opening connection to localhost:61714...
Starting SSL handshake...

No errors, certificate is already trusted

Server sent 1 certificate(s):

 1 Subject CN=localhost, OU=broker, O=Unknown, L=Unknown, ST=Unknown, C=Unknown
   Issuer  CN=localhost, OU=broker, O=Unknown, L=Unknown, ST=Unknown, C=Unknown
   sha1    f0 79 0d 04 38 5a 46 ce 86 e1 8a 20 1f 7b ab 3a 46 e4 34 5c 
   md5     3f 6c 0c 89 a8 80 29 cc f5 2d da 5c d7 3f ab 37 

Enter certificate to add to trusted keystore or 'q' to quit: [1]

5.1 Execute both Applications

Start QueueMessageProducer as a Java application and capture the output:

QueueMessageProducer output

QueueMessageProducer started ssl://localhost:61714
QueueMessageProducer completed

Start QueueMessageConsumer as a Java application and capture the output:

QueueMessageConsumeroutput

QueueMessageConsumer Waiting for messages at test.queue tcp://localhost:61616
QueueMessageConsumer Received message [ dummy message 0 ]
QueueMessageConsumer Received message [ dummy message 1 ]
QueueMessageConsumer Received message [ dummy message 2 ]
QueueMessageConsumer Received message [ dummy message 3 ]
QueueMessageConsumer Received message [ dummy message 4 ]
QueueMessageConsumer Received message [ dummy message 5 ]
QueueMessageConsumer Received message [ dummy message 6 ]
QueueMessageConsumer Received message [ dummy message 7 ]
QueueMessageConsumer Received message [ dummy message 8 ]
QueueMessageConsumer Received message [ dummy message 9 ]

Note: The QueueMessageProducer starts with an ssl connector.
Verify the ssl connector is enabled via the management web console.

Figure 2, AMQ connection SSL

6. Summary

In this tutorial, we outlined the steps to configure an AMQ server to enable the SSL/TLS transport. SSL must be enabled for Payment Card Industry (PCI) applications. Please check out this article for pro and cons about SSL for other type of applications.

7. Download the Source Code

This example builds two java applications to send and receive messages via the AMQ broker. One via secured SSL, the other not.

Download
You can download the full source code of this example here: Apache ActiveMQ SSL Example

Mary Zheng

Mary has graduated from Mechanical Engineering department at ShangHai JiaoTong University. She also holds a Master degree in Computer Science from Webster University. During her studies she has been involved with a large number of projects ranging from programming and software engineering. She works as a senior Software Engineer in the telecommunications sector where she acts as a leader and works with others to design, implement, and monitor the software solution.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Richard Yan
Richard Yan
3 years ago

Thank you very much for the detailed article! When I ran the SSL code, it gave some error messages (InstallCert gives “PKIX path building failed”, QueueMessageProducer gives “could not connect to broker URL: ssl:….” and “PKIX path building failed”. I would like to get some advice as to what caused them. Thank you in advance for your time!

Back to top button