jmswildflyactivemq-artemisundertow

How to configure the WildFly messaging-activemq subsystem with JMS to work over https


I am running WildFly 26.1 and have added the messaging-activemq subsystem to it. I want to configure it so that I can attach a remote client over https transport an send JMS messages back and forth. The way I have configured WildFly seems to work fine, but when I try to attach my client I always get an exception:

[01-17 16:06:36] [] Failed to connect to server xx.xxx.xx.227:443
javax.jms.JMSException: Failed to create session factory
    at org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory.createConnectionInternal(ActiveMQConnectionFactory.java:882)
    at org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory.createConnection(ActiveMQConnectionFactory.java:299)
    at com.tpt.common.jmsproxyclient.JMSProxyClient.connect(JMSProxyClient.java:282)
    at com.tpt.gelly.ConnectionNegotiator.establishConnection(ConnectionNegotiator.java:886)
    at com.tpt.gelly.ConnectionNegotiator.negotiateConnection(ConnectionNegotiator.java:1224)
    at com.tpt.gelly.Client.login(Client.java:1254)
    at com.tpt.gelly.Client$MultiLoginRunnable.runTraditional(Client.java:1190)
    at com.tpt.gelly.Client$MultiLoginRunnable.run(Client.java:1135)
    at com.tpt.ui.common.TPRunnable.run(TPRunnable.java:48)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:750)
Caused by: ActiveMQNotConnectedException[errorType=NOT_CONNECTED message=AMQ219007: Cannot connect to server(s). Tried with all available servers.]
    at org.apache.activemq.artemis.core.client.impl.ServerLocatorImpl.createSessionFactory(ServerLocatorImpl.java:708)
    at org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory.createConnectionInternal(ActiveMQConnectionFactory.java:880)
    ... 13 more

If the client tries to connect over http everything works, but I am unable to figure out what is needed to get a connection over https. I would like to know how I configure ActiveMQ Artemis and Undertow correctly and what properties must be set in the client application to make the connection over https. I would also like to know where I can find some good documentation for both ActiveMQ Artemis and Undertow configuration as well as ActiveMQ Artemis client connector properties.

The WildFly standalone.xml configuration for ActiveMQ Artemis connectors and acceptors that I am using is:

        <subsystem xmlns="urn:jboss:domain:messaging-activemq:13.1">
            <server name="default">

                <!--  HTTPS connector/acceptor/factory -->
                <http-connector name="https-connector" socket-binding="https" endpoint="https-acceptor">
                    <param name="sslEnabled" value="true"/> 
                </http-connector>
                <http-acceptor name="https-acceptor" http-listener="https"/>
                <connection-factory name="HttpsRemoteConnectionFactory" entries="java:jboss/exported/jms/HttpsRemoteConnectionFactory" connectors="https-connector"/>

                <!--  HTTPS throughput connector/acceptor -->
                <http-connector name="https-connector-throughput" socket-binding="https" endpoint="https-acceptor-throughput">
                    <param name="batch-delay" value="50"/>
                    <param name="sslEnabled" value="true"/> 
                </http-connector>
                <http-acceptor name="https-acceptor-throughput" http-listener="https">
                    <param name="batch-delay" value="50"/>
                    <param name="direct-deliver" value="false"/>
                </http-acceptor>
            </server>
        </subsystem>

The Undertow configuration for http & https in that same file is:

        <subsystem xmlns="urn:jboss:domain:undertow:12.0" default-server="default-server" default-virtual-host="default-host" default-servlet-container="default" default-security-domain="other" statistics-enabled="${wildfly.undertow.statistics-enabled:${wildfly.statistics-enabled:false}}">
            <buffer-cache name="default"/>
            <server name="default-server">
                <http-listener name="default" socket-binding="http" redirect-socket="https" enable-http2="true"/>            
                <https-listener name="https" socket-binding="https" ssl-context="smsSSC" enable-http2="true"/>
                <host name="default-host" alias="localhost">
                    <location name="/" handler="welcome-content"/>
                    <http-invoker http-authentication-factory="application-http-authentication"/>
                </host>
            </server>
        </subsystem>

The client code trying to connect remotely is below. I don't use JNDI because we don't want to open up another port externally. The property name constants come from org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants

    Map<String, Object> params = new HashMap<>();
    params.put(HTTP_UPGRADE_ENDPOINT_PROP_NAME, "https-acceptor");
    params.put(ACTIVEMQ_SERVER_NAME, "default");
    params.put(HTTP_UPGRADE_ENABLED_PROP_NAME, true);
    params.put(PORT_PROP_NAME, 443);
    params.put(HOST_PROP_NAME, "host");
    params.put(SSL_ENABLED_PROP_NAME, true);
    TransportConfiguration transport = new TransportConfiguration("org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnectorFactory", params);
    return ActiveMQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF, transport);

I don't know if this has anything to do with the problem, but the https socket-binding is 8443 in the WildFly configuration and we use sbin/iptables to reroute port 443 to 8443 and then block 8443 from external access using /sbin/iptables\:

      /sbin/iptables -t nat -A PREROUTING -p tcp --dport https -j REDIRECT --to-port 8443
      # any iptables cmds with 'mark' are to keep the local port closed outside
      /sbin/iptables -t mangle -A PREROUTING -p tcp --dport 8443 -j MARK --set-mark 1
      /sbin/ip6tables -t mangle -A PREROUTING -p tcp --dport 8443 -j MARK --set-mark 1

Solution

  •             <http-connector name="https-connector" socket-binding="https" endpoint="https-acceptor">
                    <param name="enabled-protocols" value="TLSv1.2"/>
                    <param name="keyStoreType" value="JKS"/>
                    <param name="trustStorePassword" value="artemisexample"/>
                    <param name="verify-host" value="false"/>
                    <param name="keyStorePassword" value="artemisexample"/>
                    <param name="trustStorePath" value="${some_path}/cacerts"/>
                    <param name="trustStoreType" value="PKCS12"/>
                    <param name="ssl-enabled" value="true"/>
                    <param name="keyStorePath" value="${some_path}/artemis.example.keystore"/>
                </http-connector>
    

    This is a sample connector ^^ for WildFly to an https-acceptor with simple configuration:

    <http-acceptor name="https-acceptor" http-listener="undertow-https"/>
    

    and

    <https-listener name="undertow-https" socket-binding="https" ssl-context="server-ssl-context"/>
    

    This looks very close to what you are doing