尝试订阅 ActiveMQ Artemis ManagementNotifications 时出现 JMSSecurity 异常
JMSSecurity exception while trying to subscribe to ActiveMQ Artemis ManagementNotifications
我正在使用 Spring 启动来执行 JNDI lookup
,因此我可以订阅 Artemis 的管理通知并确定客户端何时不再订阅特定主题。我对 JNDI 还很陌生,我的理解是我提供的代码片段导致建立与现有 Artemis 代理的连接,并因此捕获代理发送的通知。
当控件点击提供的代码片段中的 connection = cf.createConnection();
行时出现错误。
错误:
Caused by: javax.jms.JMSSecurityException: AMQ229031: Unable to validate user from /ip:port. Username: null; SSL certificate subject DN: unavailable
...
Caused by: org.apache.activemq.artemis.api.core.ActiveMQSecurityException: AMQ229031: Unable to validate user from /ip:port. Username: null; SSL certificate subject DN: unavailable
如何在 InitialContext
中包含用户名、密码、密钥库和信任库,以便不显示此错误?
我使用的代码:
@ComponentScan({"com.management.notifications"})
@SpringBootApplication
public class ManagementNotificationTestApplication {
@Value("${JMS_BROKER_TRUSTSTORE}")
private String pathToTrustStore;
public static void main(String[] args) {
SpringApplication.run(ManagementNotificationTestApplication.class);
}
@EventListener(ApplicationReadyEvent.class)
public void doSomething() throws NamingException, JMSException {
Connection connection = null;
InitialContext initialContext = null;
try {
Properties properties = new Properties();
properties.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory");
properties.setProperty(Context.PROVIDER_URL, "tcp://ipAddress:portNumber?&" + "sslEnabled=true&" +
"trustStorePath=" + pathToTrustStore + "&trustStorePassword=" + "abc");
// Step 1. Create an initial context to perform the JNDI lookup.
initialContext = new InitialContext(properties);
// Step 3. Perform a lookup on the Connection Factory
ConnectionFactory cf = (ConnectionFactory) initialContext.lookup("ConnectionFactory");
// Step 4.Create a JMS connection, a session and a producer for the queue
connection = cf.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// Step 5. Perform a lookup on the notifications topic
Topic notificationsTopic = (Topic) initialContext.lookup("topic/notificationsTopic");
// Step 6. Create a JMS message consumer for the notification queue and set its message listener
// It will display all the properties of the JMS Message
MessageConsumer notificationConsumer = session.createConsumer(notificationsTopic);
notificationConsumer.setMessageListener(new MessageListener() {
@Override
public void onMessage(final Message notif) {
System.out.println("------------------------");
System.out.println("Received notification:");
try {
Enumeration propertyNames = notif.getPropertyNames();
while (propertyNames.hasMoreElements()) {
String propertyName = (String) propertyNames.nextElement();
System.out.format(" %s: %s%n", propertyName, notif.getObjectProperty(propertyName));
}
} catch (JMSException e) {
}
System.out.println("------------------------");
}
});
// Step 7. Start the Connection to allow the consumers to receive messages
connection.start();
// Step 10. Try to create a connection with unknown user
try {
cf.createConnection("not.a.valid.user", "not.a.valid.password");
} catch (JMSException e) {
}
// sleep a little bit to be sure to receive the notification for the security
// authentication violation before leaving the example
/*Thread.sleep(2000);*/
} finally {
// Step 11. Be sure to close the resources!
if (initialContext != null) {
initialContext.close();
}
if (connection != null) {
connection.close();
}
}
}
}
您的 JNDI 代码没有任何问题。您只需要通过 createConnection(String, String)
传递用户名和密码。这是 JMS 中的标准做法。
值得注意的是,您收到身份验证错误这一事实意味着您的 SSL 配置正在运行。如果您的 SSL 配置不正确,那么您甚至在成功连接到代理并尝试进行身份验证之前就会收到 SSL 错误。
我正在使用 Spring 启动来执行 JNDI lookup
,因此我可以订阅 Artemis 的管理通知并确定客户端何时不再订阅特定主题。我对 JNDI 还很陌生,我的理解是我提供的代码片段导致建立与现有 Artemis 代理的连接,并因此捕获代理发送的通知。
当控件点击提供的代码片段中的 connection = cf.createConnection();
行时出现错误。
错误:
Caused by: javax.jms.JMSSecurityException: AMQ229031: Unable to validate user from /ip:port. Username: null; SSL certificate subject DN: unavailable
...
Caused by: org.apache.activemq.artemis.api.core.ActiveMQSecurityException: AMQ229031: Unable to validate user from /ip:port. Username: null; SSL certificate subject DN: unavailable
如何在 InitialContext
中包含用户名、密码、密钥库和信任库,以便不显示此错误?
我使用的代码:
@ComponentScan({"com.management.notifications"})
@SpringBootApplication
public class ManagementNotificationTestApplication {
@Value("${JMS_BROKER_TRUSTSTORE}")
private String pathToTrustStore;
public static void main(String[] args) {
SpringApplication.run(ManagementNotificationTestApplication.class);
}
@EventListener(ApplicationReadyEvent.class)
public void doSomething() throws NamingException, JMSException {
Connection connection = null;
InitialContext initialContext = null;
try {
Properties properties = new Properties();
properties.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory");
properties.setProperty(Context.PROVIDER_URL, "tcp://ipAddress:portNumber?&" + "sslEnabled=true&" +
"trustStorePath=" + pathToTrustStore + "&trustStorePassword=" + "abc");
// Step 1. Create an initial context to perform the JNDI lookup.
initialContext = new InitialContext(properties);
// Step 3. Perform a lookup on the Connection Factory
ConnectionFactory cf = (ConnectionFactory) initialContext.lookup("ConnectionFactory");
// Step 4.Create a JMS connection, a session and a producer for the queue
connection = cf.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// Step 5. Perform a lookup on the notifications topic
Topic notificationsTopic = (Topic) initialContext.lookup("topic/notificationsTopic");
// Step 6. Create a JMS message consumer for the notification queue and set its message listener
// It will display all the properties of the JMS Message
MessageConsumer notificationConsumer = session.createConsumer(notificationsTopic);
notificationConsumer.setMessageListener(new MessageListener() {
@Override
public void onMessage(final Message notif) {
System.out.println("------------------------");
System.out.println("Received notification:");
try {
Enumeration propertyNames = notif.getPropertyNames();
while (propertyNames.hasMoreElements()) {
String propertyName = (String) propertyNames.nextElement();
System.out.format(" %s: %s%n", propertyName, notif.getObjectProperty(propertyName));
}
} catch (JMSException e) {
}
System.out.println("------------------------");
}
});
// Step 7. Start the Connection to allow the consumers to receive messages
connection.start();
// Step 10. Try to create a connection with unknown user
try {
cf.createConnection("not.a.valid.user", "not.a.valid.password");
} catch (JMSException e) {
}
// sleep a little bit to be sure to receive the notification for the security
// authentication violation before leaving the example
/*Thread.sleep(2000);*/
} finally {
// Step 11. Be sure to close the resources!
if (initialContext != null) {
initialContext.close();
}
if (connection != null) {
connection.close();
}
}
}
}
您的 JNDI 代码没有任何问题。您只需要通过 createConnection(String, String)
传递用户名和密码。这是 JMS 中的标准做法。
值得注意的是,您收到身份验证错误这一事实意味着您的 SSL 配置正在运行。如果您的 SSL 配置不正确,那么您甚至在成功连接到代理并尝试进行身份验证之前就会收到 SSL 错误。