ActiveMQ - 创建新主题会话时的安全异常

ActiveMQ - Security exception when creating new topic session

我正在学习 jms 并找到了一个示例聊天应用程序,但是当我尝试 运行 它时,我遇到了安全异常。貌似创建新topic session的时候需要传入username和password,但是教程里没有提到这个

聊天应用程序代码:

    package ch02.chat;

import java.io.*;
import javax.jms.*;
import javax.naming.*;

public class Chat implements javax.jms.MessageListener {
    private TopicSession pubSession;
    private TopicPublisher publisher;
    private TopicConnection connection;
    private String username;

    /* Constructor used to Initialize Chat */
    public Chat(String topicFactory, String topicName, String username) 
        throws Exception {

        // Obtain a JNDI connection using the jndi.properties file
        InitialContext ctx = new InitialContext();

        // Look up a JMS connection factory and create the connection
        TopicConnectionFactory conFactory = 
            (TopicConnectionFactory)ctx.lookup(topicFactory);
        TopicConnection connection = conFactory.createTopicConnection();

        // Create two JMS session objects
        TopicSession pubSession = connection.createTopicSession(
            false, Session.AUTO_ACKNOWLEDGE);        
        TopicSession subSession = connection.createTopicSession(
            false, Session.AUTO_ACKNOWLEDGE);

        // Look up a JMS topic
        Topic chatTopic = (Topic)ctx.lookup(topicName);

        // Create a JMS publisher and subscriber. The additional parameters
        // on the createSubscriber are a message selector (null) and a true
        // value for the noLocal flag indicating that messages produced from 
        // this publisher should not be consumed by this publisher.
        TopicPublisher publisher = 
            pubSession.createPublisher(chatTopic);
        TopicSubscriber subscriber = 
            subSession.createSubscriber(chatTopic, null, true);

        // Set a JMS message listener
        subscriber.setMessageListener(this);

        // Intialize the Chat application variables
        this.connection = connection;
        this.pubSession = pubSession;
        this.publisher = publisher;
        this.username = username;

        // Start the JMS connection; allows messages to be delivered
        connection.start();
    }


    /* Receive Messages From Topic Subscriber */
    public void onMessage(Message message) {
        try {
            TextMessage textMessage = (TextMessage) message;
            System.out.println(textMessage.getText());
        } catch (JMSException jmse){ jmse.printStackTrace(); }
    }

    /* Create and Send Message Using Publisher */
    protected void writeMessage(String text) throws JMSException {
        TextMessage message = pubSession.createTextMessage();
        message.setText(username+": "+text);
        publisher.publish(message);
    }

    /* Close the JMS Connection */
    public void close() throws JMSException {
        connection.close();
    }

    /* Run the Chat Client */
    public static void main(String [] args) {
        try {
            if (args.length!=3)
                System.out.println("Factory, Topic, or username missing");

            // args[0]=topicFactory; args[1]=topicName; args[2]=username
            Chat chat = new Chat(args[0],args[1],args[2]);

            // Read from command line
            BufferedReader commandLine = new 
              java.io.BufferedReader(new InputStreamReader(System.in));

            // Loop until the word "exit" is typed
            while(true) {
                String s = commandLine.readLine();
                if (s.equalsIgnoreCase("exit")){
                    chat.close(); 
                    System.exit(0);
                } else 
                    chat.writeMessage(s);
            }
        } catch (Exception e) { e.printStackTrace(); }
    }
}

我的类路径中有以下 jndi.properties 文件:

java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory
java.naming.provider.url = tcp://localhost:61616
java.naming.security.principal=system
java.naming.security.credentials=manager

connectionFactoryNames = TopicCF
topic.topic1 = jms.topic1

Active mq 是 运行(我可以访问管理控制台)。这是我在 运行 这个应用程序和传递参数 'TopicCF topic1 Fred' 时得到的错误:

javax.jms.JMSException: User name [null] or password is invalid.
    at org.apache.activemq.util.JMSExceptionSupport.create(JMSExceptionSupport.java:49)
    at org.apache.activemq.ActiveMQConnection.syncSendPacket(ActiveMQConnection.java:1391)
    at org.apache.activemq.ActiveMQConnection.ensureConnectionInfoSent(ActiveMQConnection.java:1496)
    at org.apache.activemq.ActiveMQConnection.createSession(ActiveMQConnection.java:325)
    at org.apache.activemq.ActiveMQConnection.createTopicSession(ActiveMQConnection.java:1122)
    at ch02.chat.Chat.<init>(Chat.java:47)
    at ch02.chat.Chat.main(Chat.java:105)
Caused by: java.lang.SecurityException: User name [null] or password is invalid.
    at org.apache.activemq.security.SimpleAuthenticationBroker.addConnection(SimpleAuthenticationBroker.java:81)
    at org.apache.activemq.broker.MutableBrokerFilter.addConnection(MutableBrokerFilter.java:91)
    at org.apache.activemq.broker.TransportConnection.processAddConnection(TransportConnection.java:766)
    at org.apache.activemq.broker.jmx.ManagedTransportConnection.processAddConnection(ManagedTransportConnection.java:79)
    at org.apache.activemq.command.ConnectionInfo.visit(ConnectionInfo.java:139)
    at org.apache.activemq.broker.TransportConnection.service(TransportConnection.java:329)
    at org.apache.activemq.broker.TransportConnection.onCommand(TransportConnection.java:184)
    at org.apache.activemq.transport.MutexTransport.onCommand(MutexTransport.java:50)
    at org.apache.activemq.transport.WireFormatNegotiator.onCommand(WireFormatNegotiator.java:113)
    at org.apache.activemq.transport.AbstractInactivityMonitor.onCommand(AbstractInactivityMonitor.java:288)
    at org.apache.activemq.transport.TransportSupport.doConsume(TransportSupport.java:83)
    at org.apache.activemq.transport.tcp.TcpTransport.doRun(TcpTransport.java:214)
    at org.apache.activemq.transport.tcp.TcpTransport.run(TcpTransport.java:196)
    at java.lang.Thread.run(Thread.java:745)

我还没有在任何地方创建 topic1,但这应该会引发不同的异常。

当您建立连接时,您登录到代理的凭据在 JMS API 中定义。要传递用户名和密码,请执行以下操作:

TopicConnection connection = 
    conFactory.createTopicConnection(username, password); 

正如 Jake 所提到的,正确的方法是使用带有用户名和密码的主题连接工厂构造函数:

TopicConnection connection = 
    conFactory.createTopicConnection(username, password); 

还有一个选项,在activemq中我们可以通过在activemq.xml配置文件中添加简单的认证插件并设置anonymousAccessAllowed="true".

来允许匿名访问
<broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost" dataDirectory="${activemq.data}" schedulerSupport="true">

        <plugins>
        <!-- users and passwords -->
                <simpleAuthenticationPlugin anonymousAccessAllowed="true">
                        <users>
                                <authenticationUser username="system" password="manager" groups="admins,publishers,consumers" />
                        </users>
                </simpleAuthenticationPlugin>
        </plugins>