6 Replies Latest reply on Dec 29, 2016 10:20 AM by shaped

    Encrypted JMS Bridge between Wildfly 10 instances

    shaped Newbie

      Hi There

       

      I'm trying to setup an encrypted JMS-Bridge between two Wildfly 10 instances. Currently I cannot get the two instances to successfully establish the connection.

       

      My current setup:

      • 1 Server running Wildfly 10.0.0.Final
        • Server JMS Queue: ServerInQueue
      • 1 Client running Wildfly 10.0.0.Final
        • Client JMS Queue: ClientOutQueue

       

      Goal: JMS-Bridge for ClientOutQueue -> ServerInQueue

      Note: There are two other queues for the opposite direction (ommited for simplicity).

       

      Current state and problem:

      • Server is listening on the configured port 7212 (bridge-acceptor) and responds with the configured certificate (self-signed).
      • Configuration specified in the clients remote-connector seems to be useless.
        • Connection is made according to the specified java.naming.provider.url in the jms-bridge config.

       

      I'm aware of the thread Wildfly 10 JMS bridge over HTTPS configuration issues . But this solution uses a Core Bridge.

       

      Could anyone point me to the right direction? How can I specify that the jms-bridge connection should be encrypted?

       

      With the given configuration below I get the following exceptions (see attached file for full stacktrace):

      • Server: io.netty.handler.codec.DecoderException: javax.net.ssl.SSLException: Received fatal alert: certificate_unknown
      • Client: [https-remoting://server.name:7212 (javax.net.ssl.SSLHandshakeException: General SSLEngine problem)

       

      Server:

      <subsystem xmlns="urn:jboss:domain:messaging-activemq:1.0">
        <server name="default">
          <security-setting name="#">
            <role name="ROLE" delete-non-durable-queue="true" create-non-durable-queue="true" consume="true" send="true" />
          </security-setting>
      
          <address-setting name="#" redelivery-delay="5000" redelivery-multiplier="2" max-delivery-attempts="10" dead-letter-address="jms.queue.DLQ" />
          
          <http-connector name="http-connector" endpoint="http-acceptor" socket-binding="http" />
          <http-connector name="http-connector-throughput" endpoint="http-acceptor-throughput" socket-binding="http">
            <param name="batch-delay" value="50" />
          </http-connector>
          <in-vm-connector name="in-vm" server-id="0" />
      
          <remote-acceptor name="bridge-acceptor" socket-binding="custom-bridge">
            <param name="ssl-enabled" value="true"/>
            <param name="key-store-path" value="${jboss.server.config.dir}/keystore.jks" />
            <param name="key-store-password" value="keystore-password" />
          </remote-acceptor>
      
          <http-acceptor name="http-acceptor" http-listener="default" />
          <http-acceptor name="http-acceptor-throughput" http-listener="default">
            <param name="batch-delay" value="50" />
            <param name="direct-deliver" value="false" />
          </http-acceptor>
          <in-vm-acceptor name="in-vm" server-id="0" />
      
          <connection-factory name="InVmConnectionFactory" entries="java:/ConnectionFactory" connectors="in-vm" />
          <connection-factory name="RemoteConnectionFactory" entries="java:jboss/exported/jms/RemoteConnectionFactory" connectors="http-connector" />
          <pooled-connection-factory name="activemq-ra" transaction="xa" entries="java:/JmsXA java:jboss/DefaultJMSConnectionFactory" connectors="in-vm" />
      
          <jms-queue name="DLQ" entries="java:/jms/queue/DLQ" />
          <jms-queue name="ServerInQueue" entries="java:/jms/queue/ServerInQueue java:jboss/exported/jms/queue/ServerInQueue" />
        </server>
      </subsystem>
      ...
      <socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
        ....
        <socket-binding name="custom-bridge" port="7212" />
      </socket-binding-group>
      

       

      Client:

      <subsystem xmlns="urn:jboss:domain:messaging-activemq:1.0">
        <server name="default">
          <address-setting name="#" redelivery-delay="5000" redelivery-multiplier="2" max-delivery-attempts="10" dead-letter-address="jms.queue.DLQ" />
        
          <remote-connector name="bridge-connector" socket-binding="messaging-remote">
            <param name="ssl-enabled" value="true" />
            <param name="trust-store-path" value="${jboss.server.config.dir}/truststore.jks" />
            <param name="trust-store-password" value="truststore-password" />
      
            <!-- tried with no effect: -->
            <!--<param name="javax.net.ssl.trustStore" value="${jboss.server.config.dir}/truststore.jks" />-->
            <!--<param name="org.apache.activemq.ssl.trustStore" value="${jboss.server.config.dir}/truststore.jks" />-->
          </remote-connector>
      
          <in-vm-connector name="in-vm" server-id="0" />
          <in-vm-acceptor name="in-vm" server-id="0" />
      
          <connection-factory name="InVmConnectionFactory" entries="java:/ConnectionFactory" connectors="in-vm" />
          <connection-factory name="BridgeConnectionFactory" entries="java:jboss/exported/jms/BridgeConnectionFactory java:/jms/BridgeConnectionFactory" connectors="bridge-connector"/>
          <pooled-connection-factory name="activemq-ra" transaction="xa" entries="java:/JmsXA java:jboss/DefaultJMSConnectionFactory" connectors="in-vm" />
      
          <jms-queue name="DLQ" entries="java:/jms/queue/DLQ" />
          <jms-queue name="ClientOutQueue" entries="java:jboss/exported/jms/queue/ClientOutQueue java:/jms/queue/ClientOutQueue" />
        </server>
        <jms-bridge name="client-export-bridge" max-batch-time="100" max-batch-size="10" max-retries="-1" failure-retry-interval="10000" quality-of-service="DUPLICATES_OK">
          <source destination="java:/jms/queue/ClientOutQueue" connection-factory="ConnectionFactory" />
          <target user="jmsUser" password="jmsPassword" destination="jms/queue/ServerInQueue" connection-factory="java:/jms/BridgeConnectionFactory">
            <target-context>
              <property name="java.naming.factory.initial" value="org.jboss.naming.remote.client.InitialContextFactory" />
              <property name="java.naming.provider.url" value="https-remoting://server.name:7212" />
              <property name="java.naming.security.principal" value="jmsUser" />
              <property name="java.naming.security.credentials" value="jmsPassword" />
            </target-context>
          </target>
        </jms-bridge>
      </subsystem>
      ...
      <socket-binding-group name="standard-sockets" default-interface="public"
        ...
        <outbound-socket-binding name="messaging-remote">
          <remote-destination host="server.name" port="7212" />
        </outbound-socket-binding>
      </socket-binding-group>
      
        • 1. Re: Encrypted JMS Bridge between Wildfly 10 instances
          Justin Bertram Master

          The configuration doesn't make much sense to me.  You've got a jms-bridge configured to lookup "java:/jms/BridgeConnectionFactory" on server.name:7212, but it doesn't appear you have a connection factory with that name configured on the server (assuming server.name:7212 refers to the "Server" configuration you've provided).  Instead you've got a connection factory bound to "java:/jms/BridgeConnectionFactory" in the "Client" configuration which is using a socket pointing to server.name:7212 also which means you have the connection details defined twice.  It looks like you've combined a jms-bridge approach with a core bridge approach.  You should decide which approach you want to take and then I can help you with the configuration details.

           

          In general, I would recommend using a core bridge between instances of Wildfly.  The JMS bridge is really for interoperating between different JMS providers (e.g. the JMS provider shipped with Wildfly and IBM MQ or Tibco EMS).

          • 2. Re: Encrypted JMS Bridge between Wildfly 10 instances
            shaped Newbie

            we use wildfly/activemq on both sides and it's not planned to replace one side with a non-wildfly/activemq instance. therefore core bridge could be possible.

             

            however (from https://activemq.apache.org/artemis/docs/1.0.0/core-bridges.html):

            <bridge name="my-bridge">
               <queue-name>jms.queue.sausage-factory</queue-name>
               <forwarding-address>jms.queue.mincing-machine</forwarding-address>
               ...
            </bridge>
            

             

            according to the activemq artemis core bridge section, the queue-name is the local queue which the bridge consumes from (source). This means to me that the bridge must be defined on the wildfly-instance hosting the source queue.

             

            With jms-bridge (we have it working without encryption) we are able to define the queue on the destination wildfly-instance which then fetches to messages from the server (source). The connection will be initialized from "Client" to "Server". In our setup, it's not possible to connect from Server to Client.

             

            Please correct me if I'm wrong.

             

            In the end there should be two bridges:

            • One transfering the messages from Client to Server (ClientOutQueue -> ServerInQueue)
            • One transfering the messages from Server to Client (ServerOutQueue -> ClientInQueue)

             

            Both connections should be initialized from Client to Server. In our current setup it works with both jms-bridges defined on the client instance.

             

            If i'm wrong about the core bridge connection initialization we can also use the core bridge approach which you recommend. currently i'm not sure if its possible.

             

            I would be very grateful to you if you could help me with the configuration.

            • 3. Re: Encrypted JMS Bridge between Wildfly 10 instances
              Justin Bertram Master

              The core bridge can only "push" data so it won't be suitable for the use-case you described in your previous comment (where connections can only be made one-way and messages need to move back and forth between the machines).  The original use-case you described only had 1 bridge and it was pushing data from the client to the server so the core bridge would have been suitable for that, but I digress.

               

              The main thing I would change in your configuration is to remove the <target-context> from the "client-export-bridge" on the "Client."  Assuming you're properly imported the server's certificate into the client's truststore and all the artifacts are properly reachable on disk then I would expect everything to just work.

               

              To be clear, "javax.net.ssl.trustStore" and "org.apache.activemq.ssl.trustStore" are system properties, not transport properties so setting them on the transport wouldn't be useful.

              • 4. Re: Encrypted JMS Bridge between Wildfly 10 instances
                shaped Newbie

                Sorry for beeing not clear enough on the queues and server/client restrictions.

                 

                I removed the target-context of the jms-bridge. Now the JMS Destination jms/queue/ServerInQueue is unknown to the Client and it fails with the following error:

                 

                ERROR [org.jboss.as.controller.management-operation] (Controller Boot Thread) WFLYCTL0013: Operation ("add") failed - address: ([
                    ("subsystem" => "messaging-activemq"),
                    ("jms-bridge" => "client-export-bridge")
                ]) - failure description: {"WFLYCTL0180: Services with missing/unavailable dependencies" => ["jboss.messaging-activemq.jms-bridge.client-export-bridge is missing [jboss.naming.context.java.jms.queue.ServerInQueue]"]}
                

                 

                Is there another way to define the JMS destination without using JNDI?

                 

                If a target-context is used and the BridgeConnectionFactory is moved to the Server (like you mentioned in your first post), I was able to get the JNDI stuff from the server (see comments in config below). I also see that the certificate was added to the trusted certificates. But the connection fails with:

                 

                WARN  [org.apache.activemq.artemis.jms.bridge] (Thread-82) AMQ342010: Failed to connect JMS Bridge: javax.jms.JMSException: Failed to create session factory
                 ...
                Caused by: ActiveMQNotConnectedException[errorType=NOT_CONNECTED message=AMQ119007: Cannot connect to server(s). Tried with all available servers.]
                  at org.apache.activemq.artemis.core.client.impl.ServerLocatorImpl.createSessionFactory(ServerLocatorImpl.java:777)
                  at org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory.createConnectionInternal(ActiveMQConnectionFactory.java:724)
                  ... 9 more
                
                

                 

                 

                Server

                <subsystem xmlns="urn:jboss:domain:messaging-activemq:1.0">  
                  <server name="default">  
                    <security-setting name="#">  
                      <role name="ROLE" delete-non-durable-queue="true" create-non-durable-queue="true" consume="true" send="true" />  
                    </security-setting>  
                  
                    <address-setting name="#" redelivery-delay="5000" redelivery-multiplier="2" max-delivery-attempts="10" dead-letter-address="jms.queue.DLQ" />  
                      
                    <http-connector name="http-connector" endpoint="http-acceptor" socket-binding="http" />  
                    <http-connector name="http-connector-throughput" endpoint="http-acceptor-throughput" socket-binding="http">  
                      <param name="batch-delay" value="50" />  
                    </http-connector>  
                    <in-vm-connector name="in-vm" server-id="0" />  
                  
                  <!-- enabled if target-context is used in jms-bridge (client config) -->
                  <connection-factory name="BridgeConnectionFactory" entries="java:jboss/exported/jms/BridgeConnectionFactory" connectors="bridge-connector" />
                  <remote-connector name="bridge-connector" socket-binding="custom-bridge">
                   <param name="ssl-enabled" value="true"/>
                   <param name="trust-store-path" value="${jboss.server.config.dir}/truststore.jks" />
                   <param name="trust-store-password" value="truststore-password" />
                  </remote-connector>
                  
                  
                    <remote-acceptor name="bridge-acceptor" socket-binding="custom-bridge">  
                      <param name="ssl-enabled" value="true"/>  
                      <param name="key-store-path" value="${jboss.server.config.dir}/keystore.jks" />  
                      <param name="key-store-password" value="keystore-password" />  
                    </remote-acceptor>  
                  
                    <http-acceptor name="http-acceptor" http-listener="default" />  
                    <http-acceptor name="http-acceptor-throughput" http-listener="default">  
                      <param name="batch-delay" value="50" />  
                      <param name="direct-deliver" value="false" />  
                    </http-acceptor>  
                    <in-vm-acceptor name="in-vm" server-id="0" />  
                  
                    <connection-factory name="InVmConnectionFactory" entries="java:/ConnectionFactory" connectors="in-vm" />  
                    <pooled-connection-factory name="activemq-ra" transaction="xa" entries="java:/JmsXA java:jboss/DefaultJMSConnectionFactory" connectors="in-vm" />  
                  
                    <jms-queue name="DLQ" entries="java:/jms/queue/DLQ" />  
                    <jms-queue name="ServerInQueue" entries="java:/jms/queue/ServerInQueue java:jboss/exported/jms/queue/ServerInQueue" />  
                  </server>  
                </subsystem>  
                ...  
                <socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">  
                  ....  
                  <socket-binding name="custom-bridge" port="7212" />  
                </socket-binding-group>  
                

                 

                Client

                <subsystem xmlns="urn:jboss:domain:messaging-activemq:1.0">
                  <server name="default">
                    <address-setting name="#" redelivery-delay="5000" redelivery-multiplier="2" max-delivery-attempts="10" dead-letter-address="jms.queue.DLQ" />
                
                    <!-- enabled if no target-context is used in jms-bridge -->
                    <connection-factory name="BridgeConnectionFactory" entries="java:jboss/exported/jms/BridgeConnectionFactory java:/jms/BridgeConnectionFactory" connectors="bridge-connector"/>  
                    <remote-connector name="bridge-connector" socket-binding="messaging-remote">
                      <param name="ssl-enabled" value="true" />
                      <param name="trust-store-path" value="${jboss.server.config.dir}/truststore.jks" />
                      <param name="trust-store-password" value="truststore-password" />
                    </remote-connector>
                
                    <in-vm-connector name="in-vm" server-id="0" />
                    <in-vm-acceptor name="in-vm" server-id="0" />
                
                
                    <connection-factory name="InVmConnectionFactory" entries="java:/ConnectionFactory" connectors="in-vm" />
                    <pooled-connection-factory name="activemq-ra" transaction="xa" entries="java:/JmsXA java:jboss/DefaultJMSConnectionFactory" connectors="in-vm" />
                
                
                    <jms-queue name="DLQ" entries="java:/jms/queue/DLQ" />
                    <jms-queue name="ClientOutQueue" entries="java:jboss/exported/jms/queue/ClientOutQueue java:/jms/queue/ClientOutQueue" />
                  </server>
                  <jms-bridge name="client-export-bridge" max-batch-time="100" max-batch-size="10" max-retries="-1" failure-retry-interval="10000" quality-of-service="DUPLICATES_OK">
                  <source destination="java:/jms/queue/ClientOutQueue" connection-factory="ConnectionFactory" />
                  <target user="${jmsUser}" password="${jmsPassword}" destination="jms/queue/ServerInQueue" connection-factory="jms/BridgeConnectionFactory">
                  <!-- <target-context> -->
                  <!-- <property name="java.naming.factory.initial" value="org.jboss.naming.remote.client.InitialContextFactory" /> -->
                  <!-- <property name="java.naming.provider.url" value="http-remoting://server.name:http-port" /> -->
                  <!-- <property name="java.naming.security.principal" value="${jmsUser}" /> -->
                  <!-- <property name="java.naming.security.credentials" value="${jmsPassword}" /> -->
                  <!-- </target-context> -->
                  </target>
                  </jms-bridge>
                </subsystem>
                ...  
                <socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
                  ... 
                  <!-- enabled if no target-context is used in jms-bridge -->
                  <outbound-socket-binding name="messaging-remote">  
                    <remote-destination host="server.name" port="7212" />  
                  </outbound-socket-binding>  
                </socket-binding-group>  
                

                 

                Do you see any configuration errors?

                • 5. Re: Encrypted JMS Bridge between Wildfly 10 instances
                  Justin Bertram Master

                  I removed the target-context of the jms-bridge. Now the JMS Destination jms/queue/ServerInQueue is unknown to the Client and it fails...

                  If you want to use this approach then you can simply define the necessary queue on the "Client" machine.  As long as it matches the config of the remote queue there shouldn't be any problem.  Remember, the destination is just a POJO and looking it up in JNDI is just a convention.  There's nothing linking the destination to a particular machine.

                   

                  As far as using the target-context goes, I don't see any configuration errors there.  I suspect there is some kind of network issue between the two boxes.

                  • 6. Re: Encrypted JMS Bridge between Wildfly 10 instances
                    shaped Newbie

                    defining the queue on the client did the trick. everything works fine now. thanks Justin.