首页 > 解决方案 > JBoss EAP 7.2 通过 SSL 保护 JMS

问题描述

我通过创建安全领域并将其映射到管理界面,在 JBoss EAP 7.2 上启用了 SSL。效果很好。现在我尝试保护 JBoss EAP 上的 JMS 队列(ActiveMQ)。standalone-full.xml首先,我通过指向https-connector&指定了一个队列并提到了一个远程连接工厂acceptor

<subsystem xmlns="urn:jboss:domain:messaging-activemq:4.0">
    <server name="default">
        <journal pool-files="10"/>
        <security-setting name="#">
            <role name="guest" send="true" consume="true" create-non-durable-queue="true" delete-non-durable-queue="true"/>
        </security-setting>
        <address-setting name="#" dead-letter-address="jms.queue.DLQ" expiry-address="jms.queue.ExpiryQueue" max-size-bytes="10485760" page-size-bytes="2097152" message-counter-history-day-limit="10"/>
        <http-connector name="http-connector" socket-binding="http" endpoint="http-acceptor"/>
        <http-connector name="http-connector-throughput" socket-binding="http" endpoint="http-acceptor-throughput">
            <param name="batch-delay" value="50"/>
        </http-connector>
        <http-connector name="https-connector" socket-binding="https" endpoint="https-acceptor"/>
        <http-connector name="https-connector-throughput" socket-binding="https" endpoint="https-acceptor-throughput">
            <param name="batch-delay" value="50"/>
        </http-connector>
        <in-vm-connector name="in-vm" server-id="0">
            <param name="buffer-pooling" value="false"/>
        </in-vm-connector>
        <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>
        <http-acceptor name="https-acceptor" http-listener="https"/>
        <http-acceptor name="https-acceptor-throughput" http-listener="https">
            <param name="batch-delay" value="50"/>
            <param name="direct-deliver" value="false"/>
        </http-acceptor>
        <in-vm-acceptor name="in-vm" server-id="0">
            <param name="buffer-pooling" value="false"/>
        </in-vm-acceptor>
        <jms-queue name="ExpiryQueue" entries="java:/jms/queue/ExpiryQueue"/>
        <jms-queue name="DLQ" entries="java:/jms/queue/DLQ"/>
        <jms-queue name="testQueue" entries="java:jboss/exported/wmasTestQueue java:/jms/queue/wmasTestQueue" durable="true"/>
        <connection-factory name="InVmConnectionFactory" entries="java:/ConnectionFactory" connectors="in-vm"/>
        <connection-factory name="RemoteConnectionFactory" entries="java:jboss/exported/jms/RemoteConnectionFactory" connectors="http-connector"/>
        <connection-factory name="RemoteConnectionFactoryHttps" entries="java:jboss/exported/jms/RemoteConnectionFactoryHTTPS" connectors="https-connector"/>
        <pooled-connection-factory name="activemq-ra" entries="java:/JmsXA java:jboss/DefaultJMSConnectionFactory" connectors="in-vm" transaction="xa"/>
    </server>
</subsystem>

我已经更新了远程处理子系统,以默认使用 connector-ref 作为 https

<subsystem xmlns="urn:jboss:domain:remoting:4.0">
    <http-connector name="http-remoting-connector" connector-ref="https" security-realm="ApplicationRealm"/>
</subsystem>

当我尝试http-remoting://127.0.0.1:8443从独立的 Java 类访问时,获取连接工厂时出现以下错误

WFNAM00018: Failed to connect to remote host [Root exception is java.io.IOException: Invalid response]
    at org.wildfly.naming.client.remote.RemoteNamingProvider.getPeerIdentityForNaming(RemoteNamingProvider.java:110)
    at org.wildfly.naming.client.remote.RemoteNamingProvider.getPeerIdentityForNaming(RemoteNamingProvider.java:53)
    at org.wildfly.naming.client.NamingProvider.getPeerIdentityForNamingUsingRetry(NamingProvider.java:105)
    at org.wildfly.naming.client.remote.RemoteNamingProvider.getPeerIdentityForNamingUsingRetry(RemoteNamingProvider.java:91)
    at org.wildfly.naming.client.remote.RemoteContext.lambda$lookupNative$0(RemoteContext.java:189)
    at org.wildfly.naming.client.NamingProvider.performExceptionAction(NamingProvider.java:222)
    at org.wildfly.naming.client.remote.RemoteContext.performWithRetry(RemoteContext.java:100)
    at org.wildfly.naming.client.remote.RemoteContext.lookupNative(RemoteContext.java:188)
    at org.wildfly.naming.client.AbstractFederatingContext.lookup(AbstractFederatingContext.java:74)
    at org.wildfly.naming.client.AbstractFederatingContext.lookup(AbstractFederatingContext.java:60)
    at org.wildfly.naming.client.WildFlyRootContext.lookup(WildFlyRootContext.java:144)
    at javax.naming.InitialContext.lookup(InitialContext.java:417)
    at com.cibc.jboss.queue.PostMessage.main(PostMessage.java:43)
Caused by: java.io.IOException: Invalid response

请帮忙解决。我是否缺少任何配置。

标签: javajmsjboss-eap-7

解决方案


在 EAP 7.2 上保护 JMS 的最佳方法是使用 Elytron。使用 --interactive 模式使用 Elytron 保护服务器。这将使用在 Elyton 子系统上创建的 sslConext 设置密钥库和信任库。

您的独立服务器将如下所示;

-<tls>
-<key-stores>
-<key-store name="key-store-8ce838a4-6109-46e4-b243-a71489bb842f">
<credential-reference clear-text="password"/>
<implementation type="JKS"/>
<file relative-to="jboss.server.config.dir" path="jks-source.jks" required="false"/>
</key-store>
</key-stores>
-<key-managers>
-<key-manager name="key-manager-8ce838a4-6109-46e4-b243-a71489bb842f" key-store="key-store-8ce838a4-6109-46e4-b243-a71489bb842f">
<credential-reference clear-text="password"/>
</key-manager>
</key-managers>
-<server-ssl-contexts>
<server-ssl-context name="ssl-context-8ce838a4-6109-46e4-b243-a71489bb842f" key-manager="key-manager-8ce838a4-6109-46e4-b243-a71489bb842f" use-cipher-suites-order="false" authentication-optional="false" need-client-auth="false" want-client-auth="false" protocols="TLSv1.2" cipher-suite-filter="DEFAULT"/>
</server-ssl-contexts>
</tls>

在 activemq 子系统中的 httpconnector 上启用 ssl

-<http-connector name="http-connector2" socket-binding="https" endpoint="http-acceptor2">

<param name="ssl-enabled" value="true"/>

</http-connector>

如果客户端有自己的信任库,请务必将服务器的公共证书添加到其信任库。为了测试上述内容,我们可以使用独立的 JMS 客户端向 https-remoting://localhost:8443 发送请求。从服务器添加自签名证书以包含在 JDK 的信任库(cacerts)中是一个坏主意 - 但这是在 Jboss EAP 上测试安全 JMS 的快速选项。

public class PostMessage {

    // Set up all the default values
    private static final String DEFAULT_MESSAGE = "Hello, World! successfull";
    private static final String DEFAULT_CONNECTION_FACTORY = "jms/RemoteConnectionFactory";
    private static final String DEFAULT_DESTINATION = "TestQueue";
    private static final String DEFAULT_MESSAGE_COUNT = "1";
    private static final String DEFAULT_USERNAME = "jmsuser";
    private static final String DEFAULT_PASSWORD = "jmsuser123";
    private static final String INITIAL_CONTEXT_FACTORY = "org.wildfly.naming.client.WildFlyInitialContextFactory";
    private static final String PROVIDER_URL = "https-remoting://127.0.0.1:8443";


    public static void main(String[] args) throws JMSException {

        Context namingContext = null;

       // System.setProperty("javax.net.debug","all");

        try {
             String userName = System.getProperty("username", DEFAULT_USERNAME);
             String password = System.getProperty("password", DEFAULT_PASSWORD);

            // Set up the namingContext for the JNDI lookup
            final Properties env = new Properties();
            env.put(Context.INITIAL_CONTEXT_FACTORY, INITIAL_CONTEXT_FACTORY);
            env.put(Context.PROVIDER_URL, System.getProperty(Context.PROVIDER_URL, PROVIDER_URL));
            namingContext = new InitialContext(env);

            // Perform the JNDI lookups
            String connectionFactoryString = System.getProperty("connection.factory", DEFAULT_CONNECTION_FACTORY);
            ConnectionFactory connectionFactory = (ConnectionFactory) namingContext.lookup(connectionFactoryString);
            System.out.println("Able to look up connection factory with the naming context "  );
            Queue destination = (Queue) namingContext.lookup(DEFAULT_DESTINATION);
            System.out.println("Able to look up Queue with the naming context" );
                JMSContext jmsContext = connectionFactory.createContext(DEFAULT_USERNAME, DEFAULT_PASSWORD);
            jmsContext.createProducer().send(destination, DEFAULT_MESSAGE);
            System.out.println("><><><><><><>< MESSAGE POSTED <><><><><><><>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" );

        } catch (NamingException e) {
            e.printStackTrace();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            if (namingContext != null) {
                try {
                    namingContext.close();
                } catch (NamingException e) {
                }
            }
        }
    }
}

推荐阅读