Skip to content

Commit

Permalink
ARTEMIS-4720 Add an example of AMQP federation over SSL
Browse files Browse the repository at this point in the history
Adds an example that shows how to configure broker connections for AMQP
federation over an SSL connection.
  • Loading branch information
tabish121 authored and gemmellr committed Apr 11, 2024
1 parent 374f543 commit 064b177
Show file tree
Hide file tree
Showing 12 changed files with 558 additions and 0 deletions.
158 changes: 158 additions & 0 deletions examples/features/broker-connection/amqp-federation-over-ssl/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
<?xml version='1.0'?>
<!--
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.
-->

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.apache.activemq.examples.broker-connection</groupId>
<artifactId>broker-connections</artifactId>
<version>2.34.0-SNAPSHOT</version>
</parent>

<artifactId>amqp-federation-over-ssl</artifactId>
<packaging>jar</packaging>
<name>amqp-federation-over-ssl</name>

<properties>
<activemq.basedir>${project.basedir}/../../../..</activemq.basedir>
</properties>

<dependencies>
<dependency>
<groupId>org.apache.qpid</groupId>
<artifactId>qpid-jms-client</artifactId>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.activemq</groupId>
<artifactId>artemis-maven-plugin</artifactId>
<executions>
<execution>
<id>create0</id>
<goals>
<goal>create</goal>
</goals>
<configuration>
<ignore>${noServer}</ignore>
<instance>${basedir}/target/server0</instance>
<allowAnonymous>true</allowAnonymous>
<configuration>${basedir}/target/classes/activemq/server0</configuration>
<!-- this makes it easier in certain envs -->
<javaOptions>-Djava.net.preferIPv4Stack=true</javaOptions>
</configuration>
</execution>
<execution>
<id>create1</id>
<goals>
<goal>create</goal>
</goals>
<configuration>
<ignore>${noServer}</ignore>
<instance>${basedir}/target/server1</instance>
<allowAnonymous>true</allowAnonymous>
<configuration>${basedir}/target/classes/activemq/server1</configuration>
<!-- this makes it easier in certain envs -->
<javaOptions>-Djava.net.preferIPv4Stack=true</javaOptions>
</configuration>
</execution>
<!-- we first start broker 1, to avoid reconnecting statements -->
<execution>
<id>start1</id>
<goals>
<goal>cli</goal>
</goals>
<configuration>
<ignore>${noServer}</ignore>
<spawn>true</spawn>
<location>${basedir}/target/server1</location>
<testURI>tcp://localhost:5770?sslEnabled=true&amp;trustStorePath=activemq/server1/server-ca-truststore.p12&amp;trustStorePassword=securepass&amp;trustStoreType=PKCS12</testURI>
<args>
<param>run</param>
</args>
<name>server1</name>
</configuration>
</execution>
<execution>
<id>start0</id>
<goals>
<goal>cli</goal>
</goals>
<configuration>
<spawn>true</spawn>
<ignore>${noServer}</ignore>
<location>${basedir}/target/server0</location>
<testURI>tcp://localhost:5660?sslEnabled=true&amp;trustStorePath=activemq/server0/server-ca-truststore.p12&amp;trustStorePassword=securepass&amp;trustStoreType=PKCS12</testURI>
<args>
<param>run</param>
</args>
<name>server0</name>
</configuration>
</execution>
<execution>
<id>runClient</id>
<goals>
<goal>runClient</goal>
</goals>
<configuration>
<!-- you may have to set export MAVEN_OPTS="-Djava.net.preferIPv4Stack=true"
if you are on MacOS for instance -->
<clientClass>org.apache.activemq.artemis.jms.example.BrokerFederationExample</clientClass>
</configuration>
</execution>
<execution>
<id>stop0</id>
<goals>
<goal>stop</goal>
</goals>
<configuration>
<ignore>${noServer}</ignore>
<location>${basedir}/target/server0</location>
</configuration>
</execution>
<execution>
<id>stop1</id>
<goals>
<goal>stop</goal>
</goals>
<configuration>
<ignore>${noServer}</ignore>
<location>${basedir}/target/server1</location>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.apache.activemq.examples.broker-connection</groupId>
<artifactId>amqp-federation-over-ssl</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clean-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# AMQP Broker Connection demonstrating Federation over SSL connections

To run the example, simply type **mvn verify** from this directory, or **mvn -PnoServer verify** if you want to create and start the broker manually.

This example demonstrates how you can federate messages sent to an Address on a remote server back to the local server and also instruct the remote server to federate messages sent to a Queue on the local server back to itself over a single AMQP connection. The connection is made using a connector and acceptor with SSL configured.

The broker accepting the connection needs an acceptor on the remote to connect to which is configured as follows

<acceptor name="ssl-acceptor">tcp://localhost:5770?sslEnabled=true;keyStorePath=server-keystore.p12;keyStorePassword=securepass;keyStoreType=PKCS12</acceptor>

While the connecting broker needs to configure its broker connection URI to enable SSL and provide a trust store that include the broker certificate or certificate of the signing authority indicating the remote certificate can be trusted.

<broker-connections>
<amqp-connection uri="tcp://localhost:5770?sslEnabled=true;trustStorePath=server-ca-truststore.p12;trustStorePassword=securepass;trustStoreType=PKCS12" name="federation-example" retry-interval="100">
...
</amqp-connection>
</broker-connections>

The keystore and trustores used in the example were generated with store-generation.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* 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.
*/
package org.apache.activemq.artemis.jms.example;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;

import org.apache.qpid.jms.JmsConnectionFactory;

/**
* This example is demonstrating how messages are federated between two brokers with the
* federation configuration located on only one broker (server0) and only a single outbound
* connection is configured from server0 to server1 over an SSL connection.
*/
public class BrokerFederationExample {

public static void main(final String[] args) throws Exception {

final ConnectionFactory connectionFactoryServer0 = new JmsConnectionFactory(
"amqps://localhost:5660" +
"?transport.trustStoreLocation=src/main/resources/activemq/server0/server-ca-truststore.p12" +
"&transport.trustStoreType=PKCS12&" +
"transport.trustStorePassword=securepass");
final ConnectionFactory connectionFactoryServer1 = new JmsConnectionFactory(
"amqps://localhost:5770" +
"?transport.trustStoreLocation=src/main/resources/activemq/server1/server-ca-truststore.p12" +
"&transport.trustStoreType=PKCS12" +
"&transport.trustStorePassword=securepass");

final Connection connectionOnServer0 = connectionFactoryServer0.createConnection();
final Connection connectionOnServer1 = connectionFactoryServer1.createConnection();

connectionOnServer0.start();
connectionOnServer1.start();

final Session sessionOnServer0 = connectionOnServer0.createSession(Session.AUTO_ACKNOWLEDGE);
final Session sessionOnServer1 = connectionOnServer1.createSession(Session.AUTO_ACKNOWLEDGE);

final Topic ordersTopic = sessionOnServer0.createTopic("orders");
final Queue trackingQueue = sessionOnServer1.createQueue("tracking");

// Federation from server1 back to server0 on the orders address
final MessageProducer ordersProducerOn1 = sessionOnServer1.createProducer(ordersTopic);
final MessageConsumer ordersConsumerOn0 = sessionOnServer0.createConsumer(ordersTopic);

final TextMessage orderMessageSent = sessionOnServer1.createTextMessage("new-order");

ordersProducerOn1.send(orderMessageSent);

final TextMessage orderMessageReceived = (TextMessage) ordersConsumerOn0.receive(5_000);

System.out.println("Consumer on server 0 received order message from producer on server 1 " + orderMessageReceived.getText());

// Federation from server0 to server1 on the tracking queue
final MessageProducer trackingProducerOn0 = sessionOnServer0.createProducer(trackingQueue);
final MessageConsumer trackingConsumerOn1 = sessionOnServer1.createConsumer(trackingQueue);

final TextMessage trackingMessageSent = sessionOnServer0.createTextMessage("new-tracking-data");

trackingProducerOn0.send(trackingMessageSent);

final TextMessage trackingMessageReceived = (TextMessage) trackingConsumerOn1.receive(5_000);

System.out.println("Consumer on server 1 received tracking data from producer on server 0 " + trackingMessageReceived.getText());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
<?xml version='1.0'?>
<!--
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.
-->

<configuration xmlns="urn:activemq"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xi="http://www.w3.org/2001/XInclude"
xsi:schemaLocation="urn:activemq /schema/artemis-configuration.xsd">

<core xmlns="urn:activemq:core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:activemq:core ">

<name>0.0.0.0</name>

<persistence-enabled>false</persistence-enabled>

<journal-type>NIO</journal-type>

<!-- should the broker detect dead locks and other issues -->
<critical-analyzer>true</critical-analyzer>

<critical-analyzer-timeout>120000</critical-analyzer-timeout>

<critical-analyzer-check-period>60000</critical-analyzer-check-period>

<critical-analyzer-policy>HALT</critical-analyzer-policy>

<page-sync-timeout>44000</page-sync-timeout>

<acceptors>
<!-- Acceptor for every supported protocol -->
<acceptor name="artemis">tcp://0.0.0.0:5660?sslEnabled=true;keyStoreType=PKCS12;keyStorePath=server-keystore.p12;keyStorePassword=securepass</acceptor>
</acceptors>

<broker-connections>
<amqp-connection uri="tcp://localhost:5770?sslEnabled=true;trustStorePath=server-ca-truststore.p12;trustStorePassword=securepass;trustStoreType=PKCS12" name="federation-example" retry-interval="100">
<!-- This will create a federation connection between servers, the local
server will federate messages sent to the address 'orders' from the
remote and the remote will federate message sent to the tracking queue
on the local broker to itself. -->
<federation>
<local-address-policy name="address-federation-from-remote">
<include address-match="orders" />
</local-address-policy>
<remote-queue-policy name="queue-federation-to-remote">
<include address-match="#" queue-match="tracking" />
</remote-queue-policy>
</federation>
</amqp-connection>
</broker-connections>

<security-settings>
<security-setting match="#">
<permission type="createNonDurableQueue" roles="guest"/>
<permission type="deleteNonDurableQueue" roles="guest"/>
<permission type="createDurableQueue" roles="guest"/>
<permission type="deleteDurableQueue" roles="guest"/>
<permission type="createAddress" roles="guest"/>
<permission type="deleteAddress" roles="guest"/>
<permission type="consume" roles="guest"/>
<permission type="browse" roles="guest"/>
<permission type="send" roles="guest"/>
<permission type="manage" roles="guest"/>
</security-setting>
</security-settings>

<address-settings>
<!-- if you define auto-create on certain queues, management has to be auto-create -->
<address-setting match="activemq.management#">
<dead-letter-address>DLQ</dead-letter-address>
<expiry-address>ExpiryQueue</expiry-address>
<redelivery-delay>0</redelivery-delay>
<!-- with -1 only the global-max-size is in use for limiting -->
<max-size-bytes>-1</max-size-bytes>
<message-counter-history-day-limit>10</message-counter-history-day-limit>
<address-full-policy>PAGE</address-full-policy>
<auto-create-queues>true</auto-create-queues>
<auto-create-addresses>true</auto-create-addresses>
</address-setting>
<!--default for catch all-->
<address-setting match="#">
<dead-letter-address>DLQ</dead-letter-address>
<expiry-address>ExpiryQueue</expiry-address>
<redelivery-delay>0</redelivery-delay>
<!-- with -1 only the global-max-size is in use for limiting -->
<max-size-bytes>-1</max-size-bytes>
<message-counter-history-day-limit>10</message-counter-history-day-limit>
<address-full-policy>PAGE</address-full-policy>
<auto-create-queues>true</auto-create-queues>
<auto-create-addresses>true</auto-create-addresses>
</address-setting>
</address-settings>

<addresses>
<address name="orders">
<multicast>
</multicast>
</address>
<address name="tracking">
<anycast>
<queue name="tracking" />
</anycast>
</address>
</addresses>

</core>
</configuration>
Binary file not shown.
Binary file not shown.
Loading

0 comments on commit 064b177

Please sign in to comment.