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>
我正在学习 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>