You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by cs...@apache.org on 2026/10/17 03:34:03 UTC

(activemq) branch main updated: Clear context write cache on ACL updates (#2685)

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

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


The following commit(s) were added to refs/heads/main by this push:
     new 252f282b67 Clear context write cache on ACL updates (#2685)
252f282b67 is described below

commit 252f282b675ebd127c32f51ccc2b5af8987c083e
Author: Christopher L. Shannon <cs...@apache.org>
AuthorDate: Fri Oct 16 23:33:52 2026 -0400

    Clear context write cache on ACL updates (#2685)
---
 .../plugin/AbstractRuntimeConfigurationBroker.java | 25 +++++-
 .../plugin/AuthorizationPluginProcessor.java       | 10 +--
 .../java/JavaRuntimeConfigurationBroker.java       | 15 +---
 .../org/apache/activemq/AuthorizationTest.java     | 86 +++++++++++++++++++
 .../activemq/java/JavaAuthorizationTest.java       | 97 ++++++++++++++++++++++
 5 files changed, 212 insertions(+), 21 deletions(-)

diff --git a/activemq-runtime-config/src/main/java/org/apache/activemq/plugin/AbstractRuntimeConfigurationBroker.java b/activemq-runtime-config/src/main/java/org/apache/activemq/plugin/AbstractRuntimeConfigurationBroker.java
index c5c5ca367d..dc97241979 100644
--- a/activemq-runtime-config/src/main/java/org/apache/activemq/plugin/AbstractRuntimeConfigurationBroker.java
+++ b/activemq-runtime-config/src/main/java/org/apache/activemq/plugin/AbstractRuntimeConfigurationBroker.java
@@ -28,6 +28,9 @@ import org.apache.activemq.broker.ConnectionContext;
 import org.apache.activemq.broker.region.Destination;
 import org.apache.activemq.command.ActiveMQDestination;
 import org.apache.activemq.command.ConnectionInfo;
+import org.apache.activemq.security.AbstractAuthenticationBroker;
+import org.apache.activemq.security.AuthorizationBroker;
+import org.apache.activemq.security.AuthorizationMap;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -169,4 +172,24 @@ public class AbstractRuntimeConfigurationBroker extends BrokerFilter {
         return matchPassword.matcher(toEscape.toString()).replaceAll("password=???,");
     }
 
-}
\ No newline at end of file
+    protected void updateAuthorizationMap(final AuthorizationMap authorizationMap) {
+        try {
+            // replace authorization map - need exclusive write lock to total broker
+            AuthorizationBroker authorizationBroker =
+                    (AuthorizationBroker) getBrokerService().getBroker().getAdaptor(AuthorizationBroker.class);
+
+            authorizationBroker.setAuthorizationMap(authorizationMap);
+
+            AbstractAuthenticationBroker authenticationBroker =
+                    (AbstractAuthenticationBroker) getBrokerService().getBroker().getAdaptor(
+                            AbstractAuthenticationBroker.class);
+
+            // clear producer authorizedWriteDests cache for each SecurityContext
+            if (authenticationBroker != null) {
+                authenticationBroker.refresh();
+            }
+        } catch (Exception e) {
+            info("failed to apply modified AuthorizationMap to AuthorizationBroker", e);
+        }
+    }
+}
diff --git a/activemq-runtime-config/src/main/java/org/apache/activemq/plugin/AuthorizationPluginProcessor.java b/activemq-runtime-config/src/main/java/org/apache/activemq/plugin/AuthorizationPluginProcessor.java
index d4b8e0beec..d4f803618b 100644
--- a/activemq-runtime-config/src/main/java/org/apache/activemq/plugin/AuthorizationPluginProcessor.java
+++ b/activemq-runtime-config/src/main/java/org/apache/activemq/plugin/AuthorizationPluginProcessor.java
@@ -33,15 +33,7 @@ public class AuthorizationPluginProcessor extends DefaultConfigurationProcessor
 
     @Override
     public void modify(Object existing, Object candidate) {
-        try {
-            // replace authorization map - need exclusive write lock to total broker
-            AuthorizationBroker authorizationBroker =
-                    (AuthorizationBroker) plugin.getBrokerService().getBroker().getAdaptor(AuthorizationBroker.class);
-
-            authorizationBroker.setAuthorizationMap(fromDto(filter(candidate, DtoAuthorizationPlugin.Map.class)));
-        } catch (Exception e) {
-            plugin.info("failed to apply modified AuthorizationMap to AuthorizationBroker", e);
-        }
+        plugin.updateAuthorizationMap(fromDto(filter(candidate, DtoAuthorizationPlugin.Map.class)));
     }
 
     private AuthorizationMap fromDto(List<Object> map) {
diff --git a/activemq-runtime-config/src/main/java/org/apache/activemq/plugin/java/JavaRuntimeConfigurationBroker.java b/activemq-runtime-config/src/main/java/org/apache/activemq/plugin/java/JavaRuntimeConfigurationBroker.java
index 1448501baf..3fceab75c8 100644
--- a/activemq-runtime-config/src/main/java/org/apache/activemq/plugin/java/JavaRuntimeConfigurationBroker.java
+++ b/activemq-runtime-config/src/main/java/org/apache/activemq/plugin/java/JavaRuntimeConfigurationBroker.java
@@ -28,6 +28,7 @@ import org.apache.activemq.network.DiscoveryNetworkConnector;
 import org.apache.activemq.plugin.AbstractRuntimeConfigurationBroker;
 import org.apache.activemq.plugin.UpdateVirtualDestinationsTask;
 import org.apache.activemq.plugin.util.PolicyEntryUtil;
+import org.apache.activemq.security.AbstractAuthenticationBroker;
 import org.apache.activemq.security.AuthorizationBroker;
 import org.apache.activemq.security.AuthorizationMap;
 import org.apache.activemq.security.SimpleAuthenticationBroker;
@@ -235,16 +236,8 @@ public class JavaRuntimeConfigurationBroker extends AbstractRuntimeConfiguration
         }
     }
 
-    //authorization map
+    @Override
     public void updateAuthorizationMap(final AuthorizationMap authorizationMap) {
-        try {
-            // replace authorization map - need exclusive write lock to total broker
-            AuthorizationBroker authorizationBroker =
-                    (AuthorizationBroker) getBrokerService().getBroker().getAdaptor(AuthorizationBroker.class);
-
-            authorizationBroker.setAuthorizationMap(authorizationMap);
-        } catch (Exception e) {
-            info("failed to apply modified AuthorizationMap to AuthorizationBroker", e);
-        }
+        super.updateAuthorizationMap(authorizationMap);
     }
-}
\ No newline at end of file
+}
diff --git a/activemq-runtime-config/src/test/java/org/apache/activemq/AuthorizationTest.java b/activemq-runtime-config/src/test/java/org/apache/activemq/AuthorizationTest.java
index a253741fa2..a8f3d0ca48 100644
--- a/activemq-runtime-config/src/test/java/org/apache/activemq/AuthorizationTest.java
+++ b/activemq-runtime-config/src/test/java/org/apache/activemq/AuthorizationTest.java
@@ -16,8 +16,16 @@
  */
 package org.apache.activemq;
 
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 
+import jakarta.jms.Connection;
+import jakarta.jms.JMSSecurityException;
+import jakarta.jms.MessageProducer;
+import jakarta.jms.Session;
+import java.util.concurrent.TimeUnit;
+import org.apache.activemq.broker.BrokerService;
+import org.apache.activemq.security.DefaultAuthorizationMap;
 import org.junit.Test;
 
 public class AuthorizationTest extends AbstractAuthorizationTest {
@@ -82,6 +90,84 @@ public class AuthorizationTest extends AbstractAuthorizationTest {
         assertAllowedWrite("guest", "USERS.A");
     }
 
+    @Test
+    public void testModAddExistingProducer() throws Exception {
+        final String brokerConfig = configurationSeed + "-auth-broker";
+        applyNewConfig(brokerConfig, configurationSeed + "-users");
+        startBroker(brokerConfig);
+        assertTrue("broker alive", brokerService.isStarted());
+
+        try (Connection connection = new ActiveMQConnectionFactory("vm://localhost")
+                .createConnection("user", "user")) {
+            connection.start();
+
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            MessageProducer userProd
+                    = session.createProducer(session.createQueue("USERS.A"));
+            // can only create an anonymous, normal producer is denied for GUESTS.A
+            MessageProducer anonProd
+                    = session.createProducer(null);
+
+            // allowed
+            userProd.send(session.createTextMessage());
+            anonProd.send(session.createQueue("USERS.A"), session.createTextMessage());
+
+            // denied
+            // producer should be denied
+            assertDenied("user", "GUESTS.A");
+            assertThrows(JMSSecurityException.class, () -> anonProd.send(
+                    session.createQueue("GUESTS.A"), session.createTextMessage()));
+
+            applyNewConfig(brokerConfig, configurationSeed + "-users-guests", WAIT_FOR_CHANGE);
+
+            // all allowed
+            userProd.send(session.createTextMessage());
+            anonProd.send(session.createQueue("USERS.A"), session.createTextMessage());
+            // must create new producer, previous was not allowed
+            assertAllowedWrite("user", "GUESTS.A");
+            anonProd.send(session.createQueue("GUESTS.A"), session.createTextMessage());
+        }
+    }
+
+    @Test
+    public void testModRmExistingProducer() throws Exception {
+        final String brokerConfig = configurationSeed + "-auth-rm-broker";
+        applyNewConfig(brokerConfig, configurationSeed + "-users-guests");
+        startBroker(brokerConfig);
+        assertTrue("broker alive", brokerService.isStarted());
+
+
+        try (Connection connection = new ActiveMQConnectionFactory("vm://localhost")
+                .createConnection("user", "user")) {
+            connection.start();
+
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            MessageProducer userProd
+                    = session.createProducer(session.createQueue("USERS.A"));
+            MessageProducer guestProd
+                    = session.createProducer(session.createQueue("GUESTS.A"));
+            MessageProducer anonProd
+                    = session.createProducer(null);
+
+            // all allowed
+            userProd.send(session.createTextMessage());
+            anonProd.send(session.createQueue("USERS.A"), session.createTextMessage());
+            guestProd.send(session.createTextMessage());
+            anonProd.send(session.createQueue("GUESTS.A"), session.createTextMessage());
+
+            applyNewConfig(brokerConfig, configurationSeed + "-users", WAIT_FOR_CHANGE);
+
+            // still allowed
+            userProd.send(session.createTextMessage());
+            anonProd.send(session.createQueue("USERS.A"), session.createTextMessage());
+
+            // now denied
+            assertThrows(JMSSecurityException.class, () -> guestProd.send(session.createTextMessage()));
+            assertThrows(JMSSecurityException.class, () -> anonProd.send(
+                    session.createQueue("GUESTS.A"), session.createTextMessage()));
+        }
+    }
+
     @Test
     public void testModWithGroupClass() throws Exception {
         final String brokerConfig = configurationSeed + "-auth-add-guest-broker";
diff --git a/activemq-runtime-config/src/test/java/org/apache/activemq/java/JavaAuthorizationTest.java b/activemq-runtime-config/src/test/java/org/apache/activemq/java/JavaAuthorizationTest.java
index 8b35c1a1dc..857f67ed40 100644
--- a/activemq-runtime-config/src/test/java/org/apache/activemq/java/JavaAuthorizationTest.java
+++ b/activemq-runtime-config/src/test/java/org/apache/activemq/java/JavaAuthorizationTest.java
@@ -16,12 +16,19 @@
  */
 package org.apache.activemq.java;
 
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 
+import jakarta.jms.Connection;
+import jakarta.jms.JMSSecurityException;
+import jakarta.jms.MessageProducer;
+import jakarta.jms.Session;
 import java.util.ArrayList;
 import java.util.List;
 
+import java.util.concurrent.TimeUnit;
 import org.apache.activemq.AbstractAuthorizationTest;
+import org.apache.activemq.ActiveMQConnectionFactory;
 import org.apache.activemq.broker.BrokerPlugin;
 import org.apache.activemq.broker.BrokerService;
 import org.apache.activemq.filter.DestinationMapEntry;
@@ -95,6 +102,8 @@ public class JavaAuthorizationTest extends AbstractAuthorizationTest {
         javaConfigBroker.updateAuthorizationMap(authorizationMap);
         assertAllowed("user", "USERS.A");
         assertAllowed("guest", "GUESTS.A");
+        assertAllowedWrite("user", "USERS.A");
+        assertAllowedWrite("user", "GUESTS.A");
         assertDenied("user", "GUESTS.A");
         assertAllowedTemp("guest");
 
@@ -103,9 +112,97 @@ public class JavaAuthorizationTest extends AbstractAuthorizationTest {
 
         assertAllowed("user", "USERS.A");
         assertDenied("user", "GUESTS.A");
+        assertDeniedWrite("user", "GUESTS.A");
         assertDeniedTemp("guest");
     }
 
+    @Test
+    public void testModRmExistingProducer() throws Exception {
+        DefaultAuthorizationMap authorizationMap = buildUsersGuestsMap();
+        BrokerService brokerService = new BrokerService();
+        startBroker(brokerService);
+        assertTrue("broker alive", brokerService.isStarted());
+
+        javaConfigBroker.updateAuthorizationMap(authorizationMap);
+        TimeUnit.SECONDS.sleep(SLEEP);
+
+        try (Connection connection = new ActiveMQConnectionFactory("vm://localhost")
+                .createConnection("user", "user")) {
+            connection.start();
+
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            MessageProducer userProd
+                    = session.createProducer(session.createQueue("USERS.A"));
+            MessageProducer guestProd
+                    = session.createProducer(session.createQueue("GUESTS.A"));
+            MessageProducer anonProd
+                    = session.createProducer(null);
+
+            // all allowed
+            userProd.send(session.createTextMessage());
+            anonProd.send(session.createQueue("USERS.A"), session.createTextMessage());
+            guestProd.send(session.createTextMessage());
+            anonProd.send(session.createQueue("GUESTS.A"), session.createTextMessage());
+
+            authorizationMap = buildUsersMap();
+            javaConfigBroker.updateAuthorizationMap(authorizationMap);
+            TimeUnit.SECONDS.sleep(SLEEP);
+
+            // still allowed
+            userProd.send(session.createTextMessage());
+            anonProd.send(session.createQueue("USERS.A"), session.createTextMessage());
+
+            // now denied
+            assertThrows(JMSSecurityException.class, () -> guestProd.send(session.createTextMessage()));
+            assertThrows(JMSSecurityException.class, () -> anonProd.send(
+                    session.createQueue("GUESTS.A"), session.createTextMessage()));
+        }
+    }
+
+    @Test
+    public void testModAddExistingProducer() throws Exception {
+        DefaultAuthorizationMap authorizationMap = buildUsersMap();
+        BrokerService brokerService = new BrokerService();
+        startBroker(brokerService);
+        assertTrue("broker alive", brokerService.isStarted());
+
+        javaConfigBroker.updateAuthorizationMap(authorizationMap);
+        TimeUnit.SECONDS.sleep(SLEEP);
+
+        try (Connection connection = new ActiveMQConnectionFactory("vm://localhost")
+                .createConnection("user", "user")) {
+            connection.start();
+
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            MessageProducer userProd
+                    = session.createProducer(session.createQueue("USERS.A"));
+            // can only create an anonymous, normal producer is denied for GUESTS.A
+            MessageProducer anonProd
+                    = session.createProducer(null);
+
+            // allowed
+            userProd.send(session.createTextMessage());
+            anonProd.send(session.createQueue("USERS.A"), session.createTextMessage());
+
+            // denied
+            // producer should be denied
+            assertDenied("user", "GUESTS.A");
+            assertThrows(JMSSecurityException.class, () -> anonProd.send(
+                    session.createQueue("GUESTS.A"), session.createTextMessage()));
+
+            authorizationMap = buildUsersGuestsMap();
+            javaConfigBroker.updateAuthorizationMap(authorizationMap);
+            TimeUnit.SECONDS.sleep(SLEEP);
+
+            // all allowed
+            userProd.send(session.createTextMessage());
+            anonProd.send(session.createQueue("USERS.A"), session.createTextMessage());
+            // must create new producer, previous was not allowed
+            assertAllowedWrite("user", "GUESTS.A");
+            anonProd.send(session.createQueue("GUESTS.A"), session.createTextMessage());
+        }
+    }
+
     @Test
     public void testWildcard() throws Exception {
         DefaultAuthorizationMap authorizationMap = buildWildcardUsersGuestsMap();


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@activemq.apache.org
For additional commands, e-mail: commits-help@activemq.apache.org
For further information, visit: https://activemq.apache.org/contact