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 91d6985162 ARTEMIS-5795 Set security config using system properties
91d6985162 is described below

commit 91d69851623b2f7fcb6997057404d4c28c3d036d
Author: Domenico Francesco Bruscino <[email protected]>
AuthorDate: Fri Dec 5 08:39:53 2025 +0100

    ARTEMIS-5795 Set security config using system properties
---
 .../artemis/cli/factory/BrokerFactory.java         |  50 ++-
 .../artemis/cli/factory/BrokerFactoryTest.java     | 421 +++++++++++++++++++++
 .../cli/factory/TestBrokerFactoryHandler.java      |  87 +++++
 .../org/apache/activemq/artemis/broker/test        |  17 +
 .../api/config/ActiveMQDefaultConfiguration.java   |  18 +
 .../apache/activemq/artemis/dto/PropertyDTO.java   |   8 +
 docs/user-manual/security.adoc                     |  54 ++-
 7 files changed, 653 insertions(+), 2 deletions(-)

diff --git 
a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/factory/BrokerFactory.java
 
b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/factory/BrokerFactory.java
index 5a1a28c48c..181207239e 100644
--- 
a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/factory/BrokerFactory.java
+++ 
b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/factory/BrokerFactory.java
@@ -18,10 +18,18 @@ package org.apache.activemq.artemis.cli.factory;
 
 import java.io.IOException;
 import java.net.URI;
+import java.util.ArrayList;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Properties;
 
+import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration;
 import org.apache.activemq.artemis.cli.ConfigurationException;
 import org.apache.activemq.artemis.core.server.ActivateCallback;
 import org.apache.activemq.artemis.dto.BrokerDTO;
+import org.apache.activemq.artemis.dto.JaasSecurityDTO;
+import org.apache.activemq.artemis.dto.PropertyDTO;
+import org.apache.activemq.artemis.dto.SecurityManagerDTO;
 import org.apache.activemq.artemis.dto.ServerDTO;
 import org.apache.activemq.artemis.integration.Broker;
 import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
@@ -29,6 +37,11 @@ import org.apache.activemq.artemis.utils.FactoryFinder;
 
 public class BrokerFactory {
 
+   private static final String SECURITY_JAAS_DOMAIN_PROP_NAME = "domain";
+   private static final String SECURITY_JAAS_CERTIFICATE_DOMAIN_PROP_NAME = 
"certificateDomain";
+   private static final String SECURITY_MANAGER_CLASS_NAME_PROP_NAME = 
"className";
+   private static final String SECURITY_MANAGER_PROPERTIES_PREFIX = 
"properties.";
+
    private static BrokerDTO createBrokerConfiguration(URI configURI,
                                                       String artemisHome,
                                                       String artemisInstance,
@@ -44,7 +57,42 @@ public class BrokerFactory {
       } catch (IOException ioe) {
          throw new ConfigurationException("Invalid configuration URI, can't 
find configuration scheme: " + configURI.getScheme());
       }
-      return factory.createBroker(configURI, artemisHome, artemisInstance, 
artemisURIInstance);
+      BrokerDTO broker = factory.createBroker(configURI, artemisHome, 
artemisInstance, artemisURIInstance);
+
+      populateSecurityWithSystemProperties(broker);
+
+      return broker;
+   }
+
+   private static void populateSecurityWithSystemProperties(BrokerDTO broker) {
+      Properties systemProperties = System.getProperties();
+      String systemSecurityJaasPropertyPrefix = 
ActiveMQDefaultConfiguration.getDefaultSystemSecurityJaasPropertyPrefix();
+      String systemSecurityManagerPropertyPrefix = 
ActiveMQDefaultConfiguration.getDefaultSystemSecurityManagerPropertyPrefix();
+
+      if (systemProperties.containsKey(systemSecurityJaasPropertyPrefix + 
SECURITY_JAAS_DOMAIN_PROP_NAME)) {
+         broker.security = broker.security instanceof JaasSecurityDTO ?
+            (JaasSecurityDTO) broker.security : new JaasSecurityDTO();
+      } else if 
(systemProperties.containsKey(systemSecurityManagerPropertyPrefix + 
SECURITY_MANAGER_CLASS_NAME_PROP_NAME)) {
+         broker.security = broker.security instanceof SecurityManagerDTO ?
+            (SecurityManagerDTO) broker.security : new SecurityManagerDTO();
+      }
+
+      if (broker.security instanceof JaasSecurityDTO security) {
+         security.domain = Optional.ofNullable((String)systemProperties.get(
+            systemSecurityJaasPropertyPrefix + 
SECURITY_JAAS_DOMAIN_PROP_NAME)).orElse(security.domain);
+         security.certificateDomain = 
Optional.ofNullable((String)systemProperties.get(
+            systemSecurityJaasPropertyPrefix + 
SECURITY_JAAS_CERTIFICATE_DOMAIN_PROP_NAME)).orElse(security.certificateDomain);
+      } else if (broker.security instanceof SecurityManagerDTO security) {
+         security.className = Optional.ofNullable((String)systemProperties.get(
+            systemSecurityManagerPropertyPrefix + 
SECURITY_MANAGER_CLASS_NAME_PROP_NAME)).orElse(security.className);
+         security.properties = Objects.requireNonNullElse(security.properties, 
new ArrayList<>());
+         systemProperties.forEach((key, value) -> {
+            if (((String)key).startsWith(systemSecurityManagerPropertyPrefix + 
SECURITY_MANAGER_PROPERTIES_PREFIX)) {
+               security.properties.add(new PropertyDTO(((String)key).substring(
+                  systemSecurityManagerPropertyPrefix.length() + 
SECURITY_MANAGER_PROPERTIES_PREFIX.length()), (String)value));
+            }
+         });
+      }
    }
 
    public static BrokerDTO createBrokerConfiguration(String configuration,
diff --git 
a/artemis-cli/src/test/java/org/apache/activemq/artemis/cli/factory/BrokerFactoryTest.java
 
b/artemis-cli/src/test/java/org/apache/activemq/artemis/cli/factory/BrokerFactoryTest.java
new file mode 100644
index 0000000000..70de3643a1
--- /dev/null
+++ 
b/artemis-cli/src/test/java/org/apache/activemq/artemis/cli/factory/BrokerFactoryTest.java
@@ -0,0 +1,421 @@
+/*
+ * 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.cli.factory;
+
+import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration;
+import org.apache.activemq.artemis.dto.BrokerDTO;
+import org.apache.activemq.artemis.dto.JaasSecurityDTO;
+import org.apache.activemq.artemis.dto.PropertyDTO;
+import org.apache.activemq.artemis.dto.SecurityDTO;
+import org.apache.activemq.artemis.dto.SecurityManagerDTO;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class BrokerFactoryTest {
+
+   private static final String testBrokerConfiguration = "test://config";
+
+   private final String securityJaasPropertyPrefix = 
ActiveMQDefaultConfiguration.getDefaultSystemSecurityJaasPropertyPrefix();
+   private final String securityManagerPropertyPrefix = 
ActiveMQDefaultConfiguration.getDefaultSystemSecurityManagerPropertyPrefix();
+   private final List<String> systemPropertiesToClear = new ArrayList<>();
+
+   @BeforeEach
+   public void setUp() {
+      TestBrokerFactoryHandler.clear();
+   }
+
+   @AfterEach
+   public void tearDown() {
+      TestBrokerFactoryHandler.clear();
+      for (String property : systemPropertiesToClear) {
+         System.clearProperty(property);
+      }
+      systemPropertiesToClear.clear();
+   }
+
+   private void setSystemProperty(String key, String value) {
+      System.setProperty(key, value);
+      systemPropertiesToClear.add(key);
+   }
+
+   @Test
+   public void testCreateBrokerConfiguration() throws Exception {
+      final String testArtemisHome = "test-home";
+      final String testArtemisInstance = "test-instance";
+      final URI testArtemisURIInstance = URI.create(testArtemisInstance);
+
+      TestBrokerFactoryHandler.setBroker(new BrokerDTO());
+
+      BrokerDTO createdBroker = BrokerFactory.createBrokerConfiguration(
+         testBrokerConfiguration, testArtemisHome, testArtemisInstance, 
testArtemisURIInstance);
+
+      assertNotNull(createdBroker);
+      assertEquals(testBrokerConfiguration, 
TestBrokerFactoryHandler.getBrokerURI().toString());
+      assertEquals(testArtemisHome, TestBrokerFactoryHandler.getArtemisHome());
+      assertEquals(testArtemisInstance, 
TestBrokerFactoryHandler.getArtemisInstance());
+      assertEquals(testArtemisURIInstance, 
TestBrokerFactoryHandler.getArtemisURIInstance());
+   }
+
+   @Test
+   public void 
testCreateBrokerConfigurationWithJaasDomainFromSystemProperties() throws 
Exception {
+      setSystemProperty(securityJaasPropertyPrefix + "domain", "testDomain");
+
+      TestBrokerFactoryHandler.setBroker(new BrokerDTO());
+
+      BrokerDTO createdBroker = 
BrokerFactory.createBrokerConfiguration("test://config", null, null, null);
+
+      assertNotNull(createdBroker);
+      testJaasSecurity(createdBroker.security, "testDomain", null);
+   }
+
+   @Test
+   public void 
testCreateBrokerConfigurationWithJaasCertificateDomainFromSystemProperties() 
throws Exception {
+      setSystemProperty(securityJaasPropertyPrefix + "certificateDomain", 
"testCertificateDomain");
+
+      TestBrokerFactoryHandler.setBroker(new BrokerDTO());
+
+      BrokerDTO createdBroker = 
BrokerFactory.createBrokerConfiguration("test://config", null, null, null);
+
+      assertNotNull(createdBroker);
+      assertNull(createdBroker.security);
+   }
+
+   @Test
+   public void 
testCreateBrokerConfigurationWithJaasDomainAndCertificateDomainFromSystemProperties()
 throws Exception {
+      setSystemProperty(securityJaasPropertyPrefix + "domain", "testDomain");
+      setSystemProperty(securityJaasPropertyPrefix + "certificateDomain", 
"testCertificateDomain");
+
+      TestBrokerFactoryHandler.setBroker(new BrokerDTO());
+
+      BrokerDTO broker = 
BrokerFactory.createBrokerConfiguration("test://config", null, null, null);
+
+      assertNotNull(broker);
+      testJaasSecurity(broker.security, "testDomain", "testCertificateDomain");
+   }
+
+   @Test
+   public void 
testCreateBrokerConfigurationWithNewJaasDomainFromExistingJaasSecurityAndSystemProperties()
 throws Exception {
+      setSystemProperty(securityJaasPropertyPrefix + "domain", 
"newTestDomain");
+
+      JaasSecurityDTO  security = new JaasSecurityDTO();
+      security.domain = "testDomain";
+      security.certificateDomain = "testCertificateDomain";
+      BrokerDTO broker = new BrokerDTO();
+      broker.security = security;
+      TestBrokerFactoryHandler.setBroker(broker);
+
+      BrokerDTO createdBroker = 
BrokerFactory.createBrokerConfiguration("test://config", null, null, null);
+
+      assertNotNull(createdBroker);
+      testJaasSecurity(createdBroker.security, "newTestDomain", 
"testCertificateDomain");
+   }
+
+   @Test
+   public void 
testCreateBrokerConfigurationWithNewJaasCertificateDomainFromExistingJaasSecurityAndSystemProperties()
 throws Exception {
+      setSystemProperty(securityJaasPropertyPrefix + "certificateDomain", 
"newTestCertificateDomain");
+
+      JaasSecurityDTO  security = new JaasSecurityDTO();
+      security.domain = "testDomain";
+      security.certificateDomain = "testCertificateDomain";
+      BrokerDTO broker = new BrokerDTO();
+      broker.security = security;
+      TestBrokerFactoryHandler.setBroker(broker);
+
+      BrokerDTO createdBroker = 
BrokerFactory.createBrokerConfiguration("test://config", null, null, null);
+
+      assertNotNull(createdBroker);
+      testJaasSecurity(createdBroker.security, "testDomain", 
"newTestCertificateDomain");
+   }
+
+   @Test
+   public void 
testCreateBrokerConfigurationWithNewJaasDomainFromExistingSecurityManagerAndSystemProperties()
 throws Exception {
+      setSystemProperty(securityJaasPropertyPrefix + "domain", 
"newTestDomain");
+
+      SecurityManagerDTO  security = new SecurityManagerDTO();
+      security.className = "testClass";
+      BrokerDTO broker = new BrokerDTO();
+      broker.security = security;
+      TestBrokerFactoryHandler.setBroker(broker);
+
+      BrokerDTO createdBroker = 
BrokerFactory.createBrokerConfiguration("test://config", null, null, null);
+
+      assertNotNull(createdBroker);
+      testJaasSecurity(createdBroker.security, "newTestDomain", null);
+   }
+
+   @Test
+   public void 
testCreateBrokerConfigurationWithNewJaasCertificateDomainFromExistingSecurityManagerAndSystemProperties()
 throws Exception {
+      setSystemProperty(securityJaasPropertyPrefix + "certificateDomain", 
"newTestCertificateDomain");
+
+      SecurityManagerDTO  security = new SecurityManagerDTO();
+      security.className = "testClass";
+      BrokerDTO broker = new BrokerDTO();
+      broker.security = security;
+      TestBrokerFactoryHandler.setBroker(broker);
+
+      BrokerDTO createdBroker = 
BrokerFactory.createBrokerConfiguration("test://config", null, null, null);
+
+      assertNotNull(createdBroker);
+      testSecurityManager(createdBroker.security, "testClass", 
Collections.emptyList());
+   }
+
+   @Test
+   public void 
testCreateBrokerConfigurationWithNewJaasDomainAndCertificateDomainFromExistingJaasSecurityAndSystemProperties()
 throws Exception {
+      setSystemProperty(securityJaasPropertyPrefix + "domain", 
"newTestDomain");
+      setSystemProperty(securityJaasPropertyPrefix + "certificateDomain", 
"newTestCertificateDomain");
+
+      JaasSecurityDTO  security = new JaasSecurityDTO();
+      security.domain = "testDomain";
+      security.certificateDomain = "testCertificateDomain";
+      BrokerDTO broker = new BrokerDTO();
+      broker.security = security;
+      TestBrokerFactoryHandler.setBroker(broker);
+
+      BrokerDTO createdBroker = 
BrokerFactory.createBrokerConfiguration("test://config", null, null, null);
+
+      assertNotNull(createdBroker);
+      testJaasSecurity(createdBroker.security, "newTestDomain", 
"newTestCertificateDomain");
+   }
+
+   @Test
+   public void 
testCreateBrokerConfigurationWithNewJaasDomainAndCertificateDomainFromExistingSecurityManagerAndSystemProperties()
 throws Exception {
+      setSystemProperty(securityJaasPropertyPrefix + "domain", 
"newTestDomain");
+      setSystemProperty(securityJaasPropertyPrefix + "certificateDomain", 
"newTestCertificateDomain");
+
+      SecurityManagerDTO  security = new SecurityManagerDTO();
+      security.className = "testClassName";
+      BrokerDTO broker = new BrokerDTO();
+      broker.security = security;
+      TestBrokerFactoryHandler.setBroker(broker);
+
+      BrokerDTO createdBroker = 
BrokerFactory.createBrokerConfiguration("test://config", null, null, null);
+
+      assertNotNull(createdBroker);
+      testJaasSecurity(createdBroker.security, "newTestDomain", 
"newTestCertificateDomain");
+   }
+
+   private void testJaasSecurity(SecurityDTO security, String expectedDomain, 
String expectedCertificateDomain) throws Exception {
+      assertNotNull(security);
+      assertInstanceOf(JaasSecurityDTO.class, security);
+      JaasSecurityDTO jaasSecurity = (JaasSecurityDTO) security;
+      assertEquals(expectedDomain, jaasSecurity.domain);
+      assertEquals(expectedCertificateDomain, jaasSecurity.certificateDomain);
+   }
+
+   @Test
+   public void 
testCreateBrokerConfigurationWithSecurityManagerClassNameFromSystemProperties() 
throws Exception {
+      setSystemProperty(securityManagerPropertyPrefix + "className", 
"testClassName");
+
+      TestBrokerFactoryHandler.setBroker(new BrokerDTO());
+
+      BrokerDTO createdBroker = 
BrokerFactory.createBrokerConfiguration("test://config", null, null, null);
+
+      assertNotNull(createdBroker);
+      testSecurityManager(createdBroker.security, "testClassName", 
Collections.emptyList());
+   }
+
+   @Test
+   public void 
testCreateBrokerConfigurationWithSecurityManagerPropertiesFromSystemProperties()
 throws Exception {
+      setSystemProperty(securityManagerPropertyPrefix + "properties.testKey1", 
"testValue1");
+      setSystemProperty(securityManagerPropertyPrefix + "properties.testKey2", 
"testValue2");
+
+      TestBrokerFactoryHandler.setBroker(new BrokerDTO());
+
+      BrokerDTO createdBroker = 
BrokerFactory.createBrokerConfiguration("test://config", null, null, null);
+
+      assertNotNull(createdBroker);
+      assertNull(createdBroker.security);
+   }
+
+   @Test
+   public void 
testCreateBrokerConfigurationWithSecurityManagerClassNameAndPropertiesFromSystemProperties()
 throws Exception {
+      setSystemProperty(securityManagerPropertyPrefix + "className", 
"testClassName");
+      setSystemProperty(securityManagerPropertyPrefix + "properties.testKey1", 
"testValue1");
+      setSystemProperty(securityManagerPropertyPrefix + "properties.testKey2", 
"testValue2");
+
+      TestBrokerFactoryHandler.setBroker(new BrokerDTO());
+
+      BrokerDTO createdBroker = 
BrokerFactory.createBrokerConfiguration("test://config", null, null, null);
+
+      assertNotNull(createdBroker);
+      testSecurityManager(createdBroker.security, "testClassName", List.of(
+         new PropertyDTO("testKey1", "testValue1"), new 
PropertyDTO("testKey2", "testValue2")));
+   }
+
+   @Test
+   public void 
testCreateBrokerConfigurationWithNewSecurityManagerClassNameFromExistingSecurityManagerAndSystemProperties()
 throws Exception {
+      setSystemProperty(securityManagerPropertyPrefix + "className", 
"newTestClassName");
+
+      SecurityManagerDTO  security = new SecurityManagerDTO();
+      security.className = "testClassName";
+      security.properties = new ArrayList<>(List.of(
+         new PropertyDTO("testKey1", "testValue1"),
+         new PropertyDTO("testKey2", "testValue2")));
+      BrokerDTO broker = new BrokerDTO();
+      broker.security = security;
+      TestBrokerFactoryHandler.setBroker(broker);
+
+      BrokerDTO createdBroker = 
BrokerFactory.createBrokerConfiguration("test://config", null, null, null);
+
+      assertNotNull(createdBroker);
+      testSecurityManager(createdBroker.security, "newTestClassName", List.of(
+         new PropertyDTO("testKey1", "testValue1"), new 
PropertyDTO("testKey2", "testValue2")));
+   }
+
+   @Test
+   public void 
testCreateBrokerConfigurationWithNewSecurityManagerPropertiesFromExistingSecurityManagerAndSystemProperties()
 throws Exception {
+      setSystemProperty(securityManagerPropertyPrefix + "properties.testKey1", 
"newTestValue1");
+      setSystemProperty(securityManagerPropertyPrefix + 
"properties.newTestKey2", "newTestValue2");
+
+      SecurityManagerDTO  security = new SecurityManagerDTO();
+      security.className = "testClassName";
+      security.properties = new ArrayList<>(List.of(
+         new PropertyDTO("testKey1", "testValue1"),
+         new PropertyDTO("testKey2", "testValue2")));
+      BrokerDTO broker = new BrokerDTO();
+      broker.security = security;
+      TestBrokerFactoryHandler.setBroker(broker);
+
+      BrokerDTO createdBroker = 
BrokerFactory.createBrokerConfiguration("test://config", null, null, null);
+
+      assertNotNull(createdBroker);
+      testSecurityManager(createdBroker.security, "testClassName", List.of(
+         new PropertyDTO("testKey1", "testValue1"), new 
PropertyDTO("testKey2", "testValue2"),
+         new PropertyDTO("testKey1", "newTestValue1"), new 
PropertyDTO("newTestKey2", "newTestValue2")));
+   }
+
+   @Test
+   public void 
testCreateBrokerConfigurationWithNewSecurityManagerClassNameAndPropertiesFromExistingSecurityManagerAndSystemProperties()
 throws Exception {
+      setSystemProperty(securityManagerPropertyPrefix + "className", 
"newTestClassName");
+      setSystemProperty(securityManagerPropertyPrefix + "properties.testKey1", 
"newTestValue1");
+      setSystemProperty(securityManagerPropertyPrefix + 
"properties.newTestKey2", "newTestValue2");
+
+      SecurityManagerDTO  security = new SecurityManagerDTO();
+      security.className = "testClassName";
+      security.properties = new ArrayList<>(List.of(
+         new PropertyDTO("testKey1", "testValue1"),
+         new PropertyDTO("testKey2", "testValue2")));
+      BrokerDTO broker = new BrokerDTO();
+      broker.security = security;
+      TestBrokerFactoryHandler.setBroker(broker);
+
+      BrokerDTO createdBroker = 
BrokerFactory.createBrokerConfiguration("test://config", null, null, null);
+
+      assertNotNull(createdBroker);
+      testSecurityManager(createdBroker.security, "newTestClassName", List.of(
+         new PropertyDTO("testKey1", "testValue1"), new 
PropertyDTO("testKey2", "testValue2"),
+         new PropertyDTO("testKey1", "newTestValue1"), new 
PropertyDTO("newTestKey2", "newTestValue2")));
+   }
+
+   @Test
+   public void 
testCreateBrokerConfigurationWithNewSecurityManagerClassNameFromExistingJaasSecurityAndSystemProperties()
 throws Exception {
+      setSystemProperty(securityManagerPropertyPrefix + "className", 
"newTestClassName");
+
+      JaasSecurityDTO  security = new JaasSecurityDTO();
+      security.domain = "testDomain";
+      security.certificateDomain = "testCertificateDomain";
+      BrokerDTO broker = new BrokerDTO();
+      broker.security = security;
+      TestBrokerFactoryHandler.setBroker(broker);
+
+      BrokerDTO createdBroker = 
BrokerFactory.createBrokerConfiguration("test://config", null, null, null);
+
+      assertNotNull(createdBroker);
+      testSecurityManager(createdBroker.security, "newTestClassName", 
Collections.emptyList());
+   }
+
+   @Test
+   public void 
testCreateBrokerConfigurationWithNewSecurityManagerPropertiesFromExistingJaasSecurityAndSystemProperties()
 throws Exception {
+      setSystemProperty(securityManagerPropertyPrefix + "properties.testKey1", 
"newTestValue1");
+      setSystemProperty(securityManagerPropertyPrefix + 
"properties.newTestKey2", "newTestValue2");
+
+      JaasSecurityDTO  security = new JaasSecurityDTO();
+      security.domain = "testDomain";
+      security.certificateDomain = "testCertificateDomain";
+      BrokerDTO broker = new BrokerDTO();
+      broker.security = security;
+      TestBrokerFactoryHandler.setBroker(broker);
+
+      BrokerDTO createdBroker = 
BrokerFactory.createBrokerConfiguration("test://config", null, null, null);
+
+      assertNotNull(createdBroker);
+      testJaasSecurity(createdBroker.security, "testDomain", 
"testCertificateDomain");
+   }
+
+   @Test
+   public void 
testCreateBrokerConfigurationWithNewSecurityManagerClassNameAndPropertiesFromExistingJaasSecurityAndSystemProperties()
 throws Exception {
+      setSystemProperty(securityManagerPropertyPrefix + "className", 
"newTestClassName");
+      setSystemProperty(securityManagerPropertyPrefix + "properties.testKey1", 
"newTestValue1");
+      setSystemProperty(securityManagerPropertyPrefix + 
"properties.newTestKey2", "newTestValue2");
+
+      JaasSecurityDTO  security = new JaasSecurityDTO();
+      security.domain = "testDomain";
+      security.certificateDomain = "testCertificateDomain";
+      BrokerDTO broker = new BrokerDTO();
+      broker.security = security;
+      TestBrokerFactoryHandler.setBroker(broker);
+
+      BrokerDTO createdBroker = 
BrokerFactory.createBrokerConfiguration("test://config", null, null, null);
+
+      assertNotNull(createdBroker);
+      testSecurityManager(createdBroker.security, "newTestClassName", List.of(
+         new PropertyDTO("testKey1", "newTestValue1"), new 
PropertyDTO("newTestKey2", "newTestValue2")));
+   }
+
+   private void testSecurityManager(SecurityDTO security, String 
expectedClassName, List<PropertyDTO> expectedProperties) throws Exception {
+      assertNotNull(security);
+      assertInstanceOf(SecurityManagerDTO.class, security);
+      SecurityManagerDTO securityManager = (SecurityManagerDTO)security;
+      assertEquals(expectedClassName, securityManager.className);
+
+      if (expectedProperties != null) {
+         assertEquals(expectedProperties.size(), 
securityManager.properties.size());
+         assertTrue(expectedProperties.stream().allMatch(expectedProperty ->
+            securityManager.properties.stream().anyMatch(property ->
+               Objects.equals(expectedProperty.key, property.key) &&
+                  Objects.equals(expectedProperty.value, property.value))));
+      } else {
+         assertNull(securityManager.properties);
+      }
+   }
+
+   @Test
+   public void testJaasSecurityTakesPrecedenceOverSecurityManager() throws 
Exception {
+      setSystemProperty(securityJaasPropertyPrefix + "domain", "testDomain");
+      setSystemProperty(securityManagerPropertyPrefix + "className", 
"testClassName");
+
+      TestBrokerFactoryHandler.setBroker(new BrokerDTO());
+
+      BrokerDTO createdBroker = 
BrokerFactory.createBrokerConfiguration("test://config", null, null, null);
+
+      assertNotNull(createdBroker);
+      testJaasSecurity(createdBroker.security, "testDomain", null);
+   }
+}
diff --git 
a/artemis-cli/src/test/java/org/apache/activemq/artemis/cli/factory/TestBrokerFactoryHandler.java
 
b/artemis-cli/src/test/java/org/apache/activemq/artemis/cli/factory/TestBrokerFactoryHandler.java
new file mode 100644
index 0000000000..7bae00bc59
--- /dev/null
+++ 
b/artemis-cli/src/test/java/org/apache/activemq/artemis/cli/factory/TestBrokerFactoryHandler.java
@@ -0,0 +1,87 @@
+/*
+ * 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.cli.factory;
+
+import org.apache.activemq.artemis.dto.BrokerDTO;
+
+import java.net.URI;
+
+public class TestBrokerFactoryHandler implements BrokerFactoryHandler {
+
+   private static URI brokerURI;
+   private static String artemisHome;
+   private static String artemisInstance;
+   private static URI artemisURIInstance;
+   private static BrokerDTO broker;
+
+   public static URI getBrokerURI() {
+      return brokerURI;
+   }
+
+   public static void setBrokerURI(URI brokerURI) {
+      TestBrokerFactoryHandler.brokerURI = brokerURI;
+   }
+
+   public static String getArtemisHome() {
+      return artemisHome;
+   }
+
+   public static void setArtemisHome(String artemisHome) {
+      TestBrokerFactoryHandler.artemisHome = artemisHome;
+   }
+
+   public static String getArtemisInstance() {
+      return artemisInstance;
+   }
+
+   public static void setArtemisInstance(String artemisInstance) {
+      TestBrokerFactoryHandler.artemisInstance = artemisInstance;
+   }
+
+   public static URI getArtemisURIInstance() {
+      return artemisURIInstance;
+   }
+
+   public static void setArtemisURIInstance(URI artemisURIInstance) {
+      TestBrokerFactoryHandler.artemisURIInstance = artemisURIInstance;
+   }
+
+   public static BrokerDTO getBroker() {
+      return broker;
+   }
+
+   public static void setBroker(BrokerDTO broker) {
+      TestBrokerFactoryHandler.broker = broker;
+   }
+
+   public static void clear() {
+      brokerURI = null;
+      artemisHome = null;
+      artemisInstance = null;
+      artemisURIInstance = null;
+      broker = null;
+   }
+
+   @Override
+   public BrokerDTO createBroker(URI brokerURI, String artemisHome, String 
artemisInstance, URI artemisURIInstance) throws Exception {
+      TestBrokerFactoryHandler.brokerURI = brokerURI;
+      TestBrokerFactoryHandler.artemisHome = artemisHome;
+      TestBrokerFactoryHandler.artemisInstance = artemisInstance;
+      TestBrokerFactoryHandler.artemisURIInstance = artemisURIInstance;
+      return broker;
+   }
+}
diff --git 
a/artemis-cli/src/test/resources/META-INF/services/org/apache/activemq/artemis/broker/test
 
b/artemis-cli/src/test/resources/META-INF/services/org/apache/activemq/artemis/broker/test
new file mode 100644
index 0000000000..4259e4bb64
--- /dev/null
+++ 
b/artemis-cli/src/test/resources/META-INF/services/org/apache/activemq/artemis/broker/test
@@ -0,0 +1,17 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+class=org.apache.activemq.artemis.cli.factory.TestBrokerFactoryHandler
diff --git 
a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/config/ActiveMQDefaultConfiguration.java
 
b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/config/ActiveMQDefaultConfiguration.java
index c7f7af4ec5..3d31bb5cb9 100644
--- 
a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/config/ActiveMQDefaultConfiguration.java
+++ 
b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/config/ActiveMQDefaultConfiguration.java
@@ -571,6 +571,12 @@ public final class ActiveMQDefaultConfiguration {
 
    public static final String DEFAULT_SYSTEM_WEB_PROPERTY_PREFIX = 
"webconfig.";
 
+   public static final String DEFAULT_SYSTEM_SECURITY_PROPERTY_PREFIX = 
"securityconfig.";
+
+   public static final String DEFAULT_SYSTEM_SECURITY_JAAS_PROPERTY_PREFIX = 
"jaas.";
+
+   public static final String DEFAULT_SYSTEM_SECURITY_MANAGER_PROPERTY_PREFIX 
= "manager.";
+
    public static final String BROKER_PROPERTIES_SYSTEM_PROPERTY_NAME = 
"broker.properties";
 
    public static final String BROKER_PROPERTIES_KEY_SURROUND = "\"";
@@ -1726,6 +1732,18 @@ public final class ActiveMQDefaultConfiguration {
       return DEFAULT_SYSTEM_WEB_PROPERTY_PREFIX;
    }
 
+   public static String getDefaultSystemSecurityPropertyPrefix() {
+      return DEFAULT_SYSTEM_SECURITY_PROPERTY_PREFIX;
+   }
+
+   public static String getDefaultSystemSecurityJaasPropertyPrefix() {
+      return getDefaultSystemSecurityPropertyPrefix() + 
DEFAULT_SYSTEM_SECURITY_JAAS_PROPERTY_PREFIX;
+   }
+
+   public static String getDefaultSystemSecurityManagerPropertyPrefix() {
+      return getDefaultSystemSecurityPropertyPrefix() + 
DEFAULT_SYSTEM_SECURITY_MANAGER_PROPERTY_PREFIX;
+   }
+
    public static String getDefaultBrokerPropertiesKeySurround() {
       return BROKER_PROPERTIES_KEY_SURROUND;
    }
diff --git 
a/artemis-dto/src/main/java/org/apache/activemq/artemis/dto/PropertyDTO.java 
b/artemis-dto/src/main/java/org/apache/activemq/artemis/dto/PropertyDTO.java
index c1015a830d..9fe37f35a5 100644
--- a/artemis-dto/src/main/java/org/apache/activemq/artemis/dto/PropertyDTO.java
+++ b/artemis-dto/src/main/java/org/apache/activemq/artemis/dto/PropertyDTO.java
@@ -30,4 +30,12 @@ public class PropertyDTO {
 
    @XmlAttribute
    public String value;
+
+   public PropertyDTO() {
+   }
+
+   public PropertyDTO(String key, String value) {
+      this.key = key;
+      this.value = value;
+   }
 }
diff --git a/docs/user-manual/security.adoc b/docs/user-manual/security.adoc
index b08eb271d7..e42a3123c1 100644
--- a/docs/user-manual/security.adoc
+++ b/docs/user-manual/security.adoc
@@ -20,6 +20,55 @@ Security is enabled by default. To disable security 
completely set the `security
 </configuration>
 ----
 
+== Boot-time Security Configuration via System Properties
+
+Security configuration can be provided at boot time via system properties, 
which will override any security settings defined in `bootstrap.xml`.
+This is useful for containerized deployments or scenarios where configuration 
needs to be injected without modifying configuration files.
+
+=== JAAS Security via System Properties
+
+To configure JAAS security at boot time, use the following system properties:
+
+securityconfig.jaas.domain::
+The name of the JAAS login configuration entry to use for authentication.
+This is equivalent to the `domain` attribute of the `<jaas-security>` element 
in `bootstrap.xml`.
+
+securityconfig.jaas.certificateDomain::
+The name of the JAAS login configuration entry to use for certificate-based 
authentication.
+This is equivalent to the `certificate-domain` attribute of the 
`<jaas-security>` element in `bootstrap.xml`.
+
+For example, to start the broker with JAAS security configured via system 
properties:
+
+[,sh]
+----
+./artemis run -Dsecurityconfig.jaas.domain=MyDomain 
-Dsecurityconfig.jaas.certificateDomain=MyCertDomain
+----
+
+=== Custom Security Manager via System Properties
+
+To configure a custom security manager at boot time, use the following system 
properties:
+
+securityconfig.manager.className::
+The fully qualified class name of the security manager implementation.
+This is equivalent to the `class-name` attribute of the `<security-manager>` 
element in `bootstrap.xml`.
+
+securityconfig.manager.properties.<key>::
+Properties to pass to the security manager.
+Each property key after the `properties.` prefix will be passed as a 
configuration property to the security manager.
+
+For example, to start the broker with the basic security manager configured 
via system properties:
+
+[,sh]
+----
+./artemis run \
+  
-Dsecurityconfig.manager.className=org.apache.activemq.artemis.spi.core.security.ActiveMQBasicSecurityManager
 \
+  -Dsecurityconfig.manager.properties.bootstrapUser=admin \
+  -Dsecurityconfig.manager.properties.bootstrapPassword=admin \
+  -Dsecurityconfig.manager.properties.bootstrapRole=amq
+----
+
+NOTE: When security configuration is provided via system properties, it takes 
precedence over any security configuration in `bootstrap.xml`.
+
 == Caching Security Operations
 
 For performance reasons both *authentication and authorization is cached* 
independently.
@@ -404,6 +453,7 @@ All user & role data is stored in the broker's bindings 
journal which means any
 When using the Java Authentication and Authorization Service (JAAS) much of 
the configuration depends on which login module is used.
 However, there are a few commonalities for every case.
 The first place to look is in `bootstrap.xml`.
+Alternatively, JAAS security can be configured at boot time via system 
properties as described in <<jaas-security-via-system-properties>>.
 Here is an example using the `PropertiesLogin` JAAS login module which reads 
user, password, and role information from properties files:
 
 [,xml]
@@ -1583,7 +1633,9 @@ For details about masking passwords in broker.xml please 
see the xref:masking-pa
 
 The underpinnings of the broker's security implementation can be changed if so 
desired.
 The broker uses a component called a "security manager" to implement the 
actual authentication and authorization checks.
-By default, the broker uses 
`org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager` to 
provide JAAS integration, but users can provide their own implementation of 
`org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager5` and 
configure it in `bootstrap.xml` using the `security-manager` element, e.g.:
+By default, the broker uses 
`org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager` to 
provide JAAS integration, but users can provide their own implementation of 
`org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager5` and 
configure it in `bootstrap.xml` using the `security-manager` element.
+Alternatively, a custom security manager can be configured at boot time via 
system properties as described in 
<<custom-security-manager-via-system-properties>>.
+Here is an example of configuring a custom security manager in `bootstrap.xml`:
 
 [,xml]
 ----


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to