简体   繁体   中英

JMSSecurity exception while trying to subscribe to ActiveMQ Artemis ManagementNotifications

I'm using Spring Boot to perform a JNDI lookup so I can subscribe to Artemis' management notifications and figure out when a client is no longer subscribed to a particular topic. I'm fairly new to JNDI and my understanding is that the code snippet I've provided causes a connection to an existing Artemis broker to be established and consequently captures notifications being sent by the broker.

I get an error when control hits the connection = cf.createConnection(); line in the code snippet provided.

Error:

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

How do I include the username, password, keystore and truststore in the InitialContext so that this error doesn't show up?

Code I'm using:

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

There's nothing wrong with your JNDI code. You just need to pass the username and password via createConnection(String, String) . This is standard practice in JMS.

It's worth noting that the fact that you're getting an authentication error means that your SSL configuration is working. If your SSL config wasn't correct then you'd get an SSL error before you even made a successful connection to the broker and tried to authenticate.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM