2

I am using ActiveMQ 5.8.0, which supports AMQP 1.0 as a queue broker. I am trying to communicate with this from a Java client using the Qpid AMQP1.0 client jms library but do not see a method of specifying keystore and truststore information.

I have successfully configured a client by passing in the SSL credentials via the Java VM options (e.g. -Djavax.net.ssl.keyStore), however this is not an acceptable method for my final solution... I need to be able to specify this information from within the code.

I am currently using the createFromURL method to generate the connection from a URL that includes SSL parameters as defined here, but the keystore information (and potentially failover params) do not appear to be parsed from the URL.

String connectionUrl = "amqps://localhost/?brokerlist='tcp://localhost:5671?ssl='true'&key_store='C:/apache-activemq-5.8.0/conf/client.ks'&key_store_password='password'&trust_store='C:/apache-activemq-5.8.0/conf/client.ts'&trust_store_password='password'";
ConnectionFactoryImpl connectionFactory = ConnectionFactoryImpl.createFromURL(connectionUrl); 

Does anyone know a better way of providing the security information into the connection?

Update: Right, so doing some digging through the API I have identified that the library uses the Default SSLSocketFactory

See: org.apache.qpid.amqp_1_0.client.Connection

final Socket s;
if(ssl)
{
    s = SSLSocketFactory.getDefault().createSocket(address, port);
}

Therefore, there seems no way of specifying this information outside of the JVM options to set the default values... at least in the current version of the Qpid client library.

John Dalton
  • 249
  • 5
  • 13

3 Answers3

3

The connection URL parameters for the QPID JMS AMQP 1.0 client are a little bit different than the parameters for the previous AMQP version.

Here is an example for a connection URL that works for the 1.0 client:

amqp://myhost:myport?ssl=true&ssl-cert-alias=myalias&clientid=myclientid&remote-host=default&sync-publish=false&trust-store=C:/trusstore.ts&trust-store-password=mytrustkeypass&key-store=C:/keystore.ks&key-store-password=mykeypass

see also this link

Erik_A
  • 138
  • 8
0

Is the URL the right place to put the SSL parameters? Should the ConnectionFactory not be getting a javax.net.ssl.SSLContext and then creating the connection? (I'm not familiar with the particulars of the ActiveMQ API.)

Dan
  • 358
  • 1
  • 11
  • Thanks for the response. I believe the ConnectionFactory is responsible for setting up the queue communications so I don't have direct control over how it retrieves the SSLContext. As mentioned, if I pass in JVM options to configure the SSLContext (i.e. -D javax.net.ssl.trustStore=...) then the factory uses the keystore information and the SSL handshake works fine. The problem is I have multiple SSL communications with different keystores so I can't utilise the global JVM options. I need a way of passing SSL information for this particular connection - if that makes sense. – John Dalton Oct 04 '13 at 08:17
  • I'm more familiar with RabbitMQ, but think the APIs are similar. Their ConnectionFactory has a method useSslProtocol(javax.net.ssl.SSLContext context). The SSLContext has an init method that I think takes the parameters you are passing into the JVM. From there I assume you could create an SSLContext per connection. – Dan Oct 04 '13 at 10:47
  • Thanks again, that seems to be exactly what I was looking for, but it doesnt appear to exist. The ActiveMQ AMQP page (http://activemq.apache.org/amqp.html) directs to apache Qpid for the Java client which seems to have lost this functionality. – John Dalton Oct 04 '13 at 11:03
  • I see - the perils of replying with related knowledge rather than the particular - sorry! I don't see the ConnectionFactory on a first scan of the Qpid pages. How about org.apache.activemq.ActiveMQSslConnectionFactory which is in activemq, or do you not have that at the client end? – Dan Oct 04 '13 at 12:21
  • Thanks again. Nice try, but unfortunately that doesnt support the AMQP protocol (I run into this error: http://stackoverflow.com/questions/15788819/transport-scheme-not-recognized-amqp). This is the reason why I am using the qpid library, and I have tried posting on their mailing list for specific help. I appreciate your help though. – John Dalton Oct 04 '13 at 12:45
  • At this point I think I'd be looking at other AMQP clients! Good luck with it. – Dan Oct 04 '13 at 13:02
  • I am just going to accept this as the answer as it led me to my conclusion. See the updated original post for the answer that it does not seem possible. Thanks again Dan for the help. – John Dalton Oct 04 '13 at 14:59
0

For version 0.9.0 of QPid, which supports AMQP version 1.0.0, the client configuration page at QPID can also help with doing this programmatically.

I've also provided sample code of a successful program (NOTE: config is a class I created that stores all my configuration values):

    String ampqProtocol = "amqp";
    List<String> queryVariables = new ArrayList<String>();

    if(config.isUseSSL()) {
        queryVariables.add("transport.keyStoreLocation="+config.getKeyStorePath());
        queryVariables.add("transport.keyStorePassword="+config.getKeyStorePassword());
        queryVariables.add("transport.trustStoreLocation="+config.getTrustStorePath());
        queryVariables.add("transport.trustStorePassword="+config.getTrustStorePassword());
        queryVariables.add("transport.keyAlias="+config.getKeyStoreAlias());
        queryVariables.add("transport.contextProtocol="+config.getSslProtocol());
        queryVariables.add("transport.verifyHost="+!config.isDontValidateSSLHostname());
        ampqProtocol = "amqps";
    }
    String connectionString = ampqProtocol+"://"+config.getAddress()+":"+config.getPort();
    if(!queryVariables.isEmpty()) {
        try {
            connectionString += "?"+URLEncoder.encode(StringUtils.join(queryVariables, "&"), StandardCharsets.UTF_8.name());
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    Hashtable<Object, Object> env = new Hashtable<Object, Object>();
    env.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.qpid.jms.jndi.JmsInitialContextFactory");
    env.put("connectionfactory.myFactoryLookup", connectionString);

    Context context = null;
    ConnectionFactory connectionFactory = null;
    try {
        context = new InitialContext(env);
        connectionFactory = (ConnectionFactory) context.lookup("myFactoryLookup");
    } catch (NamingException e) {
        e.printStackTrace();
    }

    Connection connection = null;
    try {
        connection = connectionFactory.createConnection();
        connection.start();
    } catch (JMSException e) {
        e.printStackTrace();
    }
Thirlan
  • 712
  • 1
  • 8
  • 26