使用 Qpid 通过 SSL 与 AMQP 1.0 代理通信

Posted

技术标签:

【中文标题】使用 Qpid 通过 SSL 与 AMQP 1.0 代理通信【英文标题】:Communicating with AMQP 1.0 broker over SSL using Qpid 【发布时间】:2013-10-10 11:03:26 【问题描述】:

我正在使用 ActiveMQ 5.8.0,它支持 AMQP 1.0 作为队列代理。我正在尝试使用 Qpid AMQP1.0 客户端 jms 库从 Java 客户端与此通信,但没有看到指定密钥库和信任库信息的方法。

我已经通过 Java VM 选项(例如 -Djavax.net.ssl.keyStore)传入 SSL 凭据成功配置了客户端,但是对于我的最终解决方案,这不是可接受的方法...我需要能够从代码中指定此信息。

我目前正在使用 createFromURL 方法从包含定义为 here 的 SSL 参数的 URL 生成连接,但似乎没有从 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); 

有谁知道将安全信息提供给连接的更好方法?

更新: 对,所以通过 API 进行一些挖掘,我发现该库使用默认 SSLSocketFactory

参见:org.apache.qpid.amqp_1_0.client.Connection

final Socket s;
if(ssl)

    s = SSLSocketFactory.getDefault().createSocket(address, port);

因此,似乎无法在 JVM 选项之外指定此信息以设置默认值……至少在当前版本的 Qpid 客户端库中。

【问题讨论】:

【参考方案1】:

QPID JMS AMQP 1.0 客户端的连接 URL 参数与之前 AMQP 版本的参数略有不同。

以下是适用于 1.0 客户端的连接 URL 示例:

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

另见this link

【讨论】:

【参考方案2】:

URL 是放置 SSL 参数的正确位置吗? ConnectionFactory 不应该得到javax.net.ssl.SSLContext 然后创建连接吗? (我不熟悉 ActiveMQ API 的细节。)

【讨论】:

感谢您的回复。我相信 ConnectionFactory 负责设置队列通信,因此我无法直接控制它如何检索 SSLContext。如前所述,如果我传入 JVM 选项来配置 SSLContext(即 -D javax.net.ssl.trustStore=...),那么工厂使用密钥库信息并且 SSL 握手工作正常。问题是我与不同的密钥库有多个 SSL 通信,所以我不能使用全局 JVM 选项。我需要一种为此特定连接传递 SSL 信息的方法——如果这有意义的话。 我对 RabbitMQ 比较熟悉,但认为 API 类似。他们的 ConnectionFactory 有一个方法 useSslProtocol(javax.net.ssl.SSLContext context)。 SSLContext 有一个 init 方法,我认为它采用您传递给 JVM 的参数。从那里我假设您可以为每个连接创建一个 SSLContext。 再次感谢,这似乎正是我想要的,但它似乎不存在。 ActiveMQ AMQP 页面 (activemq.apache.org/amqp.html) 指向似乎已失去此功能的 Java 客户端的 apache Qpid。 我明白了 - 用相关知识而不是特定知识来回复的危险 - 抱歉!在第一次扫描 Qpid 页面时,我没有看到 ConnectionFactory。 org.apache.activemq.ActiveMQSslConnectionFactory 在activemq中怎么样,或者你在客户端没有那个? 再次感谢。不错的尝试,但不幸的是,它不支持 AMQP 协议(​​我遇到了这个错误:***.com/questions/15788819/…)。这就是我使用 qpid 库的原因,并且我尝试在他们的邮件列表上发帖寻求具体帮助。不过,我感谢您的帮助。【参考方案3】:

对于支持 AMQP 1.0.0 版的 0.9.0 版 QPid,client configuration page at QPID 也可以通过编程方式帮助完成此操作。

我还提供了一个成功程序的示例代码(注意:config 是我创建的一个类,用于存储我的所有配置值):

    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();
    

【讨论】:

以上是关于使用 Qpid 通过 SSL 与 AMQP 1.0 代理通信的主要内容,如果未能解决你的问题,请参考以下文章

从 Qpid JMS 客户端启用 AMQP 1.0 插件连接到 RabbitMQ 3.7.18 时出现错误匹配错误

解决Qpid与RabbitMQ端口冲突问题(epmd reports: node rabbit’ not running at all),RabbitMQ 3.11修改AMQP端口

AMQP Qpid Proton - 无法将消息发送到超过 256 个队列

使用 Spring、ActiveMQ 和 Qpid 进行集成测试

如何使用 qpid-jms-client 创建 RabbitMQ 持久队列?

如何使用 JMS 和 AMQP 1.0 设置 RabbitMQ?