3

I am trying to connect to an ActiveMQ message broker which uses SSL. I am getting the error:

invalid uri: ssl://myserver.com:61613 [invalid broker(s): 'NoneType' object has no attribute 'groupdict']

Example code taken from stompest documentation: I only changed server, user and pass:

import time
from stompest.config import StompConfig
from stompest.sync import Stomp

while True:
    try:
        client = Stomp(StompConfig("ssl://myserver.com:61613", login = 'me', passcode = 'me', version = "1.2" ))
        client.connect(versions = ["1.2"], host = vhost, heartBeats = (0, 60000))   #CONNECT
        subscription = client.subscribe(destination, {"ack": "client", "id": "0"})  #SUBSCRIBE
        while True:
            frame = client.receiveFrame()
            try:
                print frame.body
                client.ack(frame)   #ACK
            except:
                print "Error: Can't handle message received, NACKing"
                client.nack(frame)  #NACK
    except Exception, e:
        # Reconnect on exception
        print "Exception handled, reconnecting...\nDetail:\n%s" % e
        try:
            client.disconnect()
        except:
            pass
        time.sleep(5)

I believe Stompest can handle SSL, but I can't find any reference in the documentation.

Thanks

fuglede
  • 17,388
  • 2
  • 54
  • 99
user636322
  • 1,151
  • 3
  • 12
  • 23

1 Answers1

0

Your StompConfig has to be provided with an SSLContext with a configuration of the SSL connection. Exactly how this one should look will depend on the specifics of your setup, so let us have a look at some of the options.

For more information on how to set up ActiveMQ to use SSL in general, see this Apache guide, and this StackOverflow question which addresses the same issue but for stomp.py.

No validation

If all you need is a quick and dirty connection with no validation of broker or client -- that is, a connection which would be susceptible to MITM attacks from an active attacker -- then you can supply an SSLContext with validation disabled:

import ssl
sslContext = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
# Let's at least disable some of the older SSL protocols
sslContext.options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1 | ssl.OP_NO_SSLv3
sslContext.check_hostname = False
sslContext.verify_mode = ssl.CERT_NONE

With this, all you need to do is to provide sslContext to your StompConfig:

client = Stomp(StompConfig('ssl://myserver.com:61613', login='me', passcode='me', version='1.2', sslContext=sslContext))

Broker certificate validation

The first improvement over this would be to verify the certificate provided by the server. Assuming that you are using a self-signed certificate (as opposed to one signed by a certificate authority), you can simply provide your SSLContext with the certificate directly:

First, on the broker, export the certificate from its keystore, which we will assume is stored in a file called broker.ks by using the Java keytool through

keytool -exportcert -rfc -alias broker -keystore broker.ks -file broker.pem

Now, move broker.pem to the Python client and change the sslContext configuration as follows:

sslContext = ssl.create_default_context(cafile='broker.pem')
sslContext.check_hostname = True
sslContext.verify_mode = ssl.CERT_REQUIRED

Client certificate validation

ActiveMQ servers can also be set up to only allow connections from clients with predefined certificates. Assuming that you have a PEM encoded client certificate in client.pem, have stored the private key in client.key (cf. e.g. the first part of this answer), and set up ApacheMQ to validate that certificate (cf. the third part of the same answer), then all you need to do to have stompest use that pair for the connection is to call

sslContext.load_cert_chain('client.pem', 'client.key')

as part of the configuration.

fuglede
  • 17,388
  • 2
  • 54
  • 99