You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@artemis.apache.org by jb...@apache.org on 2026/06/02 17:46:04 UTC

(artemis) branch main updated: ARTEMIS-6057 treat fqqn with wildcards as exact match

This is an automated email from the ASF dual-hosted git repository.

jbertram pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/artemis.git


The following commit(s) were added to refs/heads/main by this push:
     new fde82ef9cf ARTEMIS-6057 treat fqqn with wildcards as exact match
fde82ef9cf is described below

commit fde82ef9cfe376798a59270a7fcab74b71091d8b
Author: Gary Tully <ga...@gmail.com>
AuthorDate: Wed May 13 13:29:30 2026 +0100

    ARTEMIS-6057 treat fqqn with wildcards as exact match
    
    in security settings, fqqn are treated as an exact match, but when they
    contain a wildcard are being ignored for exact match semantics in error
---
 .../impl/HierarchicalObjectRepository.java         |   5 +-
 .../jms/client/WildcardOnboardSecureTest.java      | 136 +++++++++++++++++++++
 2 files changed, 139 insertions(+), 2 deletions(-)

diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/settings/impl/HierarchicalObjectRepository.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/settings/impl/HierarchicalObjectRepository.java
index 03dbe7c303..be6737f272 100644
--- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/settings/impl/HierarchicalObjectRepository.java
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/settings/impl/HierarchicalObjectRepository.java
@@ -37,6 +37,7 @@ import org.apache.activemq.artemis.core.server.ActiveMQServerLogger;
 import org.apache.activemq.artemis.core.settings.HierarchicalRepository;
 import org.apache.activemq.artemis.core.settings.HierarchicalRepositoryChangeListener;
 import org.apache.activemq.artemis.core.settings.Mergeable;
+import org.apache.activemq.artemis.utils.CompositeAddress;
 import org.apache.activemq.artemis.utils.collections.ConcurrentHashSet;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -203,7 +204,7 @@ public class HierarchicalObjectRepository<T> implements HierarchicalRepository<T
       lock.writeLock().lock();
       try {
          // an exact match (i.e. one without wildcards) won't impact any other matches so no need to clear the cache
-         if (wildcardConfiguration.isWild(modifiedMatch)) {
+         if (wildcardConfiguration.isWild(modifiedMatch) && !CompositeAddress.isFullyQualified(modifiedMatch)) {
             clearCache();
          } else if (modifiedMatch != null && cache.containsKey(modifiedMatch)) {
             cache.remove(modifiedMatch);
@@ -216,7 +217,7 @@ public class HierarchicalObjectRepository<T> implements HierarchicalRepository<T
          Match<T> match1 = new Match<>(modifiedMatch, value, wildcardConfiguration, literal);
          if (literal) {
             literalMatches.put(modifiedMatch, match1);
-         } else if (wildcardConfiguration.isWild(modifiedMatch)) {
+         } else if (wildcardConfiguration.isWild(modifiedMatch) && !CompositeAddress.isFullyQualified(modifiedMatch)) {
             wildcardMatches.put(modifiedMatch, match1);
          } else {
             exactMatches.put(modifiedMatch, match1);
diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/client/WildcardOnboardSecureTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/client/WildcardOnboardSecureTest.java
new file mode 100644
index 0000000000..8fa424f35e
--- /dev/null
+++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/client/WildcardOnboardSecureTest.java
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.activemq.artemis.tests.integration.jms.client;
+
+import org.apache.activemq.artemis.api.core.QueueConfiguration;
+import org.apache.activemq.artemis.api.core.RoutingType;
+import org.apache.activemq.artemis.core.config.CoreAddressConfiguration;
+import org.apache.activemq.artemis.core.security.Role;
+import org.apache.activemq.artemis.core.server.ActiveMQServer;
+import org.apache.activemq.artemis.core.settings.HierarchicalRepository;
+import org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager;
+import org.apache.activemq.artemis.tests.util.JMSTestBase;
+import org.apache.activemq.artemis.utils.CompositeAddress;
+import org.junit.jupiter.api.Test;
+
+import javax.jms.Connection;
+import javax.jms.DeliveryMode;
+import javax.jms.JMSSecurityException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.ObjectMessage;
+import javax.jms.Queue;
+import javax.jms.QueueBrowser;
+import javax.jms.Session;
+import javax.jms.Topic;
+
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+public class WildcardOnboardSecureTest extends JMSTestBase {
+
+   private final String publishTo = "test.topic.A";
+   private final String subscribeToWildcard = "test.topic.*";
+   private final String clientId = "id1";
+   private final String subscriberName = "sub1";
+
+   @Test
+   public void testConsumeFromExistingWildcardWithJustConsumePermissionViaFqqnAsExactMatch() throws Exception {
+      final String userPass = "joe";
+      Session sendSession = createSession(null, userPass);
+      MessageProducer producerA = createProducer(sendSession, publishTo);
+
+      ObjectMessage received;
+      try (MessageConsumer consumerWC = createConsumer(subscribeToWildcard, userPass)) {
+         Message message = sendSession.createObjectMessage(1);
+         producerA.send(message);
+         received = (ObjectMessage) consumerWC.receive(500);
+      }
+      assertNotNull(received);
+      assertNotNull(received.getObject());
+   }
+
+   @Test
+   public void testConsumeFromExistingWildcardWithNoPermFails() {
+      assertThrows(JMSSecurityException.class, () -> createConsumer(subscribeToWildcard, "deny"));
+   }
+
+   @Test
+   public void testBrowserPermissionDeniedOnFqqn() {
+      assertThrows(JMSSecurityException.class, () -> {
+         Session session = createSession(clientId, "joe");
+         Queue queue = session.createQueue(CompositeAddress.toFullyQualified(subscribeToWildcard, clientId + "." + subscriberName));
+         QueueBrowser browser = session.createBrowser(queue);
+         final Enumeration enumeration = browser.getEnumeration();
+      });
+   }
+
+   @Override
+   protected boolean useSecurity() {
+      return true;
+   }
+
+   @Override
+   protected void extraServerConfig(ActiveMQServer server) {
+      HierarchicalRepository<Set<Role>> securityRepository = server.getSecurityRepository();
+      ActiveMQJAASSecurityManager securityManager = (ActiveMQJAASSecurityManager) server.getSecurityManager();
+      securityManager.getConfiguration().addUser("deny", "deny");
+      securityManager.getConfiguration().addUser("joe", "joe");
+      securityManager.getConfiguration().addRole("joe", "joe");
+      Role joe = new Role("joe", true, true, false, false, false, false, false, false, false, false, false, false);
+      Set<Role> roles = new HashSet<>();
+      // no auto create permissions
+      roles.add(joe);
+
+      securityRepository.addMatch(publishTo, roles);
+      // note fqqn contains a wildcard but because it is a fqqn it is treated as an exact match
+      securityRepository.addMatch(CompositeAddress.toFullyQualified(subscribeToWildcard, clientId + "." + subscriberName), roles);
+      securityManager.getConfiguration().addRole("joe", "joe");
+      // pre create address and consumer queue as only send/consume permissions exist
+      server.getConfiguration().addAddressConfiguration(new CoreAddressConfiguration().setName(publishTo).addRoutingType(RoutingType.MULTICAST));
+      server.getConfiguration().addQueueConfiguration(QueueConfiguration.of(clientId + "." + subscriberName).setAddress(subscribeToWildcard).setRoutingType(RoutingType.MULTICAST));
+   }
+
+   private Session createSession(String clientId, String userPass) throws Exception {
+      Connection connection = cf.createConnection(userPass, userPass);
+      if (clientId != null) {
+         connection.setClientID(clientId);
+      }
+      connection.start();
+      addConnection(connection);
+
+      return connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+   }
+
+   private MessageProducer createProducer(Session session, String topicName) throws Exception {
+      Topic topic = session.createTopic(topicName);
+      MessageProducer producer = session.createProducer(topic);
+      producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
+      return producer;
+   }
+
+   private MessageConsumer createConsumer(String topicName, String userPass) throws Exception {
+      Session session = createSession(clientId, userPass);
+      Topic topic = session.createTopic(topicName);
+      return session.createDurableConsumer(topic, subscriberName);
+   }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@artemis.apache.org
For additional commands, e-mail: commits-help@artemis.apache.org