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

brusdev 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 d8004df2ca ARTEMIS-5830 - add jaas config to broker properties
d8004df2ca is described below

commit d8004df2caf47e2bea6a81c90b6c3c21bc64693a
Author: Gary Tully <[email protected]>
AuthorDate: Thu Dec 18 16:59:34 2025 +0000

    ARTEMIS-5830 - add jaas config to broker properties
---
 .../artemis/core/config/Configuration.java         |   2 +
 .../artemis/core/config/JaasAppConfiguration.java  |  78 +++++++++++++
 .../core/config/JaasAppConfigurationEntry.java     | 100 +++++++++++++++++
 .../core/config/impl/ConfigurationImpl.java        |  37 ++++++-
 .../spi/core/security/jaas/GuestLoginModule.java   |   4 +-
 .../core/config/JaasAppConfigurationEntryTest.java | 121 +++++++++++++++++++++
 .../core/config/JaasAppConfigurationTest.java      |  61 +++++++++++
 docs/user-manual/configuration-index.adoc          |   9 ++
 .../security/SecurityPerAcceptorJmsTest.java       |  84 +++++++++++++-
 .../integration/server/ConfigurationTest.java      |   8 ++
 10 files changed, 496 insertions(+), 8 deletions(-)

diff --git 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/Configuration.java
 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/Configuration.java
index 8a892f6598..dfbc499c08 100644
--- 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/Configuration.java
+++ 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/Configuration.java
@@ -1538,4 +1538,6 @@ public interface Configuration {
    default boolean isUsingDatabasePersistence() {
       return getStoreConfiguration() != null && 
getStoreConfiguration().getStoreType() == StoreConfiguration.StoreType.DATABASE;
    }
+
+   Map<String, JaasAppConfiguration> getJaasConfigs();
 }
diff --git 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/JaasAppConfiguration.java
 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/JaasAppConfiguration.java
new file mode 100644
index 0000000000..73ad330389
--- /dev/null
+++ 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/JaasAppConfiguration.java
@@ -0,0 +1,78 @@
+/*
+ * 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.core.config;
+
+import javax.security.auth.login.AppConfigurationEntry;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+public class JaasAppConfiguration implements Serializable {
+
+   private static final long serialVersionUID = -651209063030767325L;
+
+   private String name;
+
+   private List<JaasAppConfigurationEntry> modules = new ArrayList<>();
+
+   public JaasAppConfiguration() {
+   }
+
+   public String getName() {
+      return name;
+   }
+
+   public JaasAppConfiguration setName(String name) {
+      this.name = name;
+      return this;
+   }
+
+   public List<JaasAppConfigurationEntry> getModules() {
+      return modules;
+   }
+
+   // help the properties setter
+   public JaasAppConfiguration addModule(JaasAppConfigurationEntry entry) {
+      modules.add(entry);
+      return this;
+   }
+
+   public static AppConfigurationEntry[] 
asAppConfigurationEntry(JaasAppConfiguration jaasAppConfiguration) {
+      if (jaasAppConfiguration == null) {
+         return null;
+      }
+      AppConfigurationEntry[] entries = new 
AppConfigurationEntry[jaasAppConfiguration.getModules().size()];
+      for (int i = 0; i < jaasAppConfiguration.getModules().size(); i++) {
+         JaasAppConfigurationEntry jaasAppConfigurationEntry = 
jaasAppConfiguration.getModules().get(i);
+         entries[i] = new 
AppConfigurationEntry(jaasAppConfigurationEntry.getLoginModuleClass(), 
jaasAppConfigurationEntry.getLoginModuleControlFlag(), 
jaasAppConfigurationEntry.getParams());
+      }
+      return entries;
+   }
+
+   @Override
+   public boolean equals(Object o) {
+      if (o == null || getClass() != o.getClass()) return false;
+      JaasAppConfiguration that = (JaasAppConfiguration) o;
+      return Objects.equals(name, that.name) && Objects.equals(modules, 
that.modules);
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hash(name, modules);
+   }
+}
diff --git 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/JaasAppConfigurationEntry.java
 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/JaasAppConfigurationEntry.java
new file mode 100644
index 0000000000..934ec57eee
--- /dev/null
+++ 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/JaasAppConfigurationEntry.java
@@ -0,0 +1,100 @@
+/*
+ * 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.core.config;
+
+import javax.security.auth.login.AppConfigurationEntry;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+public class JaasAppConfigurationEntry implements Serializable {
+
+   private static final long serialVersionUID = -651209063030767725L;
+
+   private String name;
+
+   private String loginModuleClass;
+
+   private String controlFlag;
+
+   private Map<String, String> params = new HashMap<>();
+
+   public JaasAppConfigurationEntry() {
+   }
+
+   public String getName() {
+      return name;
+   }
+
+   public String getLoginModuleClass() {
+      return loginModuleClass;
+   }
+
+   public Map<String, String> getParams() {
+      return params;
+   }
+
+   public String getControlFlag() {
+      return controlFlag;
+   }
+
+   public JaasAppConfigurationEntry setName(String name) {
+      this.name = name;
+      return this;
+   }
+
+   public JaasAppConfigurationEntry setLoginModuleClass(String 
loginModuleClass) {
+      this.loginModuleClass = loginModuleClass;
+      return this;
+   }
+
+   public JaasAppConfigurationEntry setParams(Map<String, String> params) {
+      this.params = params;
+      return this;
+   }
+
+   public void setControlFlag(String controlFlag) {
+      this.controlFlag = controlFlag;
+      getLoginModuleControlFlag();
+   }
+
+   AppConfigurationEntry.LoginModuleControlFlag getLoginModuleControlFlag() {
+      if (this.controlFlag == null || this.controlFlag.isEmpty() || 
this.controlFlag.equals("required")) {
+         return AppConfigurationEntry.LoginModuleControlFlag.REQUIRED;
+      } else if (this.controlFlag.equals("requisite")) {
+         return AppConfigurationEntry.LoginModuleControlFlag.REQUISITE;
+      } else if (this.controlFlag.equals("optional")) {
+         return AppConfigurationEntry.LoginModuleControlFlag.OPTIONAL;
+      } else if (this.controlFlag.equals("sufficient")) {
+         return AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT;
+      }
+      throw new IllegalArgumentException("Unknown control flag: " + 
this.controlFlag);
+   }
+
+   @Override
+   public boolean equals(Object o) {
+      if (o == null || getClass() != o.getClass()) return false;
+      JaasAppConfigurationEntry that = (JaasAppConfigurationEntry) o;
+      return Objects.equals(name, that.name) && 
Objects.equals(loginModuleClass, that.loginModuleClass) && 
Objects.equals(controlFlag, that.controlFlag) && Objects.equals(params, 
that.params);
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hash(name, loginModuleClass, controlFlag, params);
+   }
+}
diff --git 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/impl/ConfigurationImpl.java
 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/impl/ConfigurationImpl.java
index a81dda1a4d..f8a71e017f 100644
--- 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/impl/ConfigurationImpl.java
+++ 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/impl/ConfigurationImpl.java
@@ -57,6 +57,7 @@ import java.util.Objects;
 import java.util.Properties;
 import java.util.Set;
 import java.util.Stack;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Consumer;
@@ -86,6 +87,7 @@ import 
org.apache.activemq.artemis.core.config.CoreQueueConfiguration;
 import org.apache.activemq.artemis.core.config.DivertConfiguration;
 import org.apache.activemq.artemis.core.config.FederationConfiguration;
 import org.apache.activemq.artemis.core.config.HAPolicyConfiguration;
+import org.apache.activemq.artemis.core.config.JaasAppConfiguration;
 import org.apache.activemq.artemis.core.config.MetricsConfiguration;
 import org.apache.activemq.artemis.core.config.StoreConfiguration;
 import org.apache.activemq.artemis.core.config.WildcardConfiguration;
@@ -159,9 +161,11 @@ import org.apache.commons.beanutils.expression.Resolver;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import javax.security.auth.login.AppConfigurationEntry;
+
 import static 
org.apache.activemq.artemis.utils.PasswordMaskingUtil.isEncMasked;
 
-public class ConfigurationImpl implements Configuration, Serializable {
+public class ConfigurationImpl extends javax.security.auth.login.Configuration 
implements Configuration, Serializable {
 
    private static final Logger logger = 
LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
@@ -478,6 +482,8 @@ public class ConfigurationImpl implements Configuration, 
Serializable {
 
    private boolean purgePageFolders = 
ActiveMQDefaultConfiguration.getPurgePageFolders();
 
+   private Map<String, JaasAppConfiguration> jaasConfigs = new 
ConcurrentHashMap<>();
+
    /**
     * Parent folder for all data folders.
     */
@@ -671,6 +677,26 @@ public class ConfigurationImpl implements Configuration, 
Serializable {
       if (!beanProperties.isEmpty()) {
          populateWithProperties(target, name, beanProperties);
       }
+      if (!jaasConfigs.isEmpty()) {
+         initJaasConfigOverride();
+      }
+   }
+
+   private javax.security.auth.login.Configuration defaultJaasConfiguration = 
null;
+   private void initJaasConfigOverride() {
+      if (defaultJaasConfiguration == null) {
+         defaultJaasConfiguration = 
javax.security.auth.login.Configuration.getConfiguration();
+         javax.security.auth.login.Configuration.setConfiguration(this);
+      }
+   }
+
+   @Override
+   public AppConfigurationEntry[] getAppConfigurationEntry(String realm) {
+      if (getJaasConfigs().containsKey(realm)) {
+         return 
JaasAppConfiguration.asAppConfigurationEntry(getJaasConfigs().get(realm));
+      } else {
+         return defaultJaasConfiguration.getAppConfigurationEntry(realm);
+      }
    }
 
    public void populateWithProperties(final Object target, final String 
propsId, Map<String, Object> beanProperties) throws InvocationTargetException, 
IllegalAccessException {
@@ -1002,6 +1028,15 @@ public class ConfigurationImpl implements Configuration, 
Serializable {
       }
    }
 
+   @Override
+   public Map<String, JaasAppConfiguration> getJaasConfigs() {
+      return jaasConfigs;
+   }
+
+   public void addJaasConfig(JaasAppConfiguration config) {
+      jaasConfigs.put(config.getName(), config);
+   }
+
    private void writeProperties(FileWriter writer) throws Exception {
       final BeanUtilsBean beanUtilsBean = new BeanUtilsBean();
       beanUtilsBean.getPropertyUtils().addBeanIntrospector(new 
FluentPropertyBeanIntrospectorWithIgnores());
diff --git 
a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/GuestLoginModule.java
 
b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/GuestLoginModule.java
index 0c4fa77bcb..da2f59d930 100644
--- 
a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/GuestLoginModule.java
+++ 
b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/GuestLoginModule.java
@@ -41,8 +41,8 @@ public class GuestLoginModule implements AuditLoginModule {
 
    private static final Logger logger = 
LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
-   private static final String GUEST_USER = 
"org.apache.activemq.jaas.guest.user";
-   private static final String GUEST_ROLE = 
"org.apache.activemq.jaas.guest.role";
+   public static final String GUEST_USER = 
"org.apache.activemq.jaas.guest.user";
+   public static final String GUEST_ROLE = 
"org.apache.activemq.jaas.guest.role";
 
    private String userName = "guest";
    private String roleName = "guests";
diff --git 
a/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/JaasAppConfigurationEntryTest.java
 
b/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/JaasAppConfigurationEntryTest.java
new file mode 100644
index 0000000000..a0d14d2af6
--- /dev/null
+++ 
b/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/JaasAppConfigurationEntryTest.java
@@ -0,0 +1,121 @@
+/*
+ * 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.core.config;
+
+import org.junit.jupiter.api.Test;
+
+import javax.security.auth.login.AppConfigurationEntry;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class JaasAppConfigurationEntryTest {
+
+   @Test
+   void testEquals() {
+      JaasAppConfigurationEntry a = new JaasAppConfigurationEntry();
+      JaasAppConfigurationEntry b = new JaasAppConfigurationEntry();
+
+      assertTrue(a.equals(b));
+
+      a.setName("test");
+      assertFalse(a.equals(b));
+
+      b.setName("test");
+      assertTrue(a.equals(b));
+
+      a.setControlFlag("optional");
+      assertFalse(a.equals(b));
+
+      b.setControlFlag("optional");
+      assertTrue(a.equals(b));
+
+      a.setLoginModuleClass("module");
+      assertFalse(a.equals(b));
+
+      b.setLoginModuleClass("module");
+      assertTrue(a.equals(b));
+
+      a.getParams().put("key1", "value1");
+      assertFalse(a.equals(b));
+
+      b.getParams().put("key1", "value1");
+      assertTrue(a.equals(b));
+
+      a.getParams().put("key2", "value1");
+      assertFalse(a.equals(b));
+      b.getParams().put("key2", "value2");
+      assertFalse(a.equals(b));
+   }
+
+   @Test
+   void testHashCode() {
+
+      JaasAppConfigurationEntry a = new JaasAppConfigurationEntry();
+      JaasAppConfigurationEntry b = new JaasAppConfigurationEntry();
+      assertEquals(a.hashCode(), b.hashCode());
+
+      a.setName("test");
+      assertNotEquals(a.hashCode(), b.hashCode());
+
+      b.setName("test");
+      assertEquals(a.hashCode(), b.hashCode());
+
+      a.setControlFlag("optional");
+      assertNotEquals(a.hashCode(), b.hashCode());
+
+      b.setControlFlag("optional");
+      assertEquals(a.hashCode(), b.hashCode());
+
+      a.setLoginModuleClass("module");
+      assertNotEquals(a.hashCode(), b.hashCode());
+
+      b.setLoginModuleClass("module");
+      assertEquals(a.hashCode(), b.hashCode());
+
+      a.getParams().put("key1", "value1");
+      assertNotEquals(a.hashCode(), b.hashCode());
+
+      b.getParams().put("key1", "value1");
+      assertEquals(a.hashCode(), b.hashCode());
+
+   }
+
+   @Test
+   void setControlFlag() {
+      assertThrowsExactly(IllegalArgumentException.class, () -> new 
JaasAppConfigurationEntry().setControlFlag("null"));
+
+      JaasAppConfigurationEntry a = new JaasAppConfigurationEntry();
+      a.setControlFlag(null);
+      assertEquals(AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, 
a.getLoginModuleControlFlag());
+
+      a.setControlFlag("required");
+      assertEquals(AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, 
a.getLoginModuleControlFlag());
+
+      a.setControlFlag("optional");
+      assertEquals(AppConfigurationEntry.LoginModuleControlFlag.OPTIONAL, 
a.getLoginModuleControlFlag());
+
+      a.setControlFlag("requisite");
+      assertEquals(AppConfigurationEntry.LoginModuleControlFlag.REQUISITE, 
a.getLoginModuleControlFlag());
+
+      a.setControlFlag("sufficient");
+      assertEquals(AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT, 
a.getLoginModuleControlFlag());
+   }
+}
\ No newline at end of file
diff --git 
a/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/JaasAppConfigurationTest.java
 
b/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/JaasAppConfigurationTest.java
new file mode 100644
index 0000000000..fc38b81979
--- /dev/null
+++ 
b/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/JaasAppConfigurationTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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.core.config;
+
+import org.junit.jupiter.api.Test;
+
+import javax.security.auth.login.AppConfigurationEntry;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+
+class JaasAppConfigurationTest {
+
+   @Test
+   void asAppConfigurationEntry() {
+      JaasAppConfiguration underTest = new JaasAppConfiguration();
+      underTest.setName("test");
+      JaasAppConfigurationEntry entry = new JaasAppConfigurationEntry();
+      entry.setName("test");
+      entry.setLoginModuleClass("a");
+
+      underTest.addModule(entry);
+      underTest.addModule(entry);
+
+      assertEquals(2, 
JaasAppConfiguration.asAppConfigurationEntry(underTest).length);
+      assertEquals(AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, 
JaasAppConfiguration.asAppConfigurationEntry(underTest)[0].getControlFlag());
+   }
+
+   @Test
+   void testEquals() {
+      JaasAppConfiguration a = new JaasAppConfiguration();
+      JaasAppConfiguration b = new JaasAppConfiguration();
+      assertEquals(a, b);
+
+      a.setName(this.getClass().getName());
+      assertNotEquals(a, b);
+      b.setName(this.getClass().getName());
+      assertEquals(a, b);
+      JaasAppConfigurationEntry entry = new JaasAppConfigurationEntry();
+      entry.setName(this.getClass().getName());
+      a.getModules().add(entry);
+      assertNotEquals(a, b);
+      b.getModules().add(entry);
+      assertEquals(a, b);
+   }
+}
\ No newline at end of file
diff --git a/docs/user-manual/configuration-index.adoc 
b/docs/user-manual/configuration-index.adoc
index e90943b62a..db0836fa09 100644
--- a/docs/user-manual/configuration-index.adoc
+++ b/docs/user-manual/configuration-index.adoc
@@ -115,6 +115,15 @@ acceptorConfigurations.tcp.params.port=61616
  . set the acceptor named "tcp" 'HOST' parameter to localhost
  . set the acceptor named "tcp" 'PORT' parameter to 61616
 
+=== JAAS
+Broker properties can configure JAAS via the `jaasConfigs` collection, this 
provides a means to dynamically configure the jaas realms accessed by the 
broker. The jaas configuration provider will look first for any realm 
configured in the `jaasConfigs` collection before delegating to the platform 
defaults.
+For example, to configure the `guestRealm` and use it from the above `tcp` 
acceptor, configure properties of the form:
+
+----
+acceptorConfigurations.tcp.params.securityDomain=guestRealm
+jaasConfigs.guestRealm.modules.guest.loginModuleClass=org.apache.activemq.artemis.spi.core.security.jaas.GuestLoginModule
+jaasConfigs.guestRealm.modules.guest.controlFlag=required
+----
 ==== Usage
 
 The `artemis run` command script supports `--properties <path to properties 
files comma list>` where properties file paths can be configured.
diff --git 
a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/SecurityPerAcceptorJmsTest.java
 
b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/SecurityPerAcceptorJmsTest.java
index 49e09024b5..271055deb8 100644
--- 
a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/SecurityPerAcceptorJmsTest.java
+++ 
b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/SecurityPerAcceptorJmsTest.java
@@ -16,41 +16,56 @@
  */
 package org.apache.activemq.artemis.tests.integration.security;
 
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.fail;
-
 import javax.jms.Connection;
 import javax.jms.ConnectionFactory;
 import javax.jms.JMSException;
+import javax.jms.JMSSecurityException;
 import javax.jms.MessageConsumer;
 import javax.jms.MessageProducer;
 import javax.jms.QueueBrowser;
 import javax.jms.Session;
+import javax.security.auth.Subject;
 import java.lang.management.ManagementFactory;
 import java.net.URL;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Set;
+import java.util.Stack;
 
+import org.apache.activemq.artemis.api.core.ActiveMQException;
 import org.apache.activemq.artemis.api.core.QueueConfiguration;
 import org.apache.activemq.artemis.api.core.RoutingType;
 import org.apache.activemq.artemis.api.core.SimpleString;
+import org.apache.activemq.artemis.core.config.impl.ConfigurationImpl;
+import org.apache.activemq.artemis.core.persistence.OperationContext;
 import org.apache.activemq.artemis.core.security.Role;
 import org.apache.activemq.artemis.core.server.ActiveMQServer;
 import org.apache.activemq.artemis.core.server.ActiveMQServers;
 import org.apache.activemq.artemis.core.server.impl.AddressInfo;
+import 
org.apache.activemq.artemis.core.server.plugin.ActiveMQServerSessionPlugin;
 import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
+import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
+import org.apache.activemq.artemis.spi.core.protocol.SessionCallback;
 import 
org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager;
+import org.apache.activemq.artemis.spi.core.security.jaas.GuestLoginModule;
+import org.apache.activemq.artemis.spi.core.security.jaas.UserPrincipal;
 import org.apache.activemq.artemis.tests.extensions.parameterized.Parameter;
 import 
org.apache.activemq.artemis.tests.extensions.parameterized.ParameterizedTestExtension;
 import org.apache.activemq.artemis.tests.extensions.parameterized.Parameters;
 import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
 import org.apache.qpid.jms.JmsConnectionFactory;
+import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.TestTemplate;
 import org.junit.jupiter.api.extension.ExtendWith;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
 @ExtendWith(ParameterizedTestExtension.class)
 public class SecurityPerAcceptorJmsTest extends ActiveMQTestBase {
 
@@ -68,7 +83,7 @@ public class SecurityPerAcceptorJmsTest extends 
ActiveMQTestBase {
    }
 
    @Parameter(index = 0)
-   public Protocol protocol;
+   public Protocol protocol = Protocol.AMQP;
 
    static {
       String path = System.getProperty("java.security.auth.login.config");
@@ -93,11 +108,70 @@ public class SecurityPerAcceptorJmsTest extends 
ActiveMQTestBase {
             cf = new ActiveMQConnectionFactory(URL);
             break;
          case OPENWIRE:
-            cf = new org.apache.activemq.ActiveMQConnectionFactory(URL);
+            cf = new org.apache.activemq.ActiveMQConnectionFactory(URL + 
"?jms.watchTopicAdvisories=false");
             break;
          case AMQP:
             cf = new JmsConnectionFactory("amqp://localhost:61616");
+      }
+   }
 
+   @TestTemplate
+   public void testJAASSecurityManagerRealmFromPropertiesConfigOk() throws 
Exception {
+      ActiveMQServer server = 
addServer(ActiveMQServers.newActiveMQServer(createDefaultInVMConfig().setSecurityEnabled(true).setResolveProtocols(true).addAcceptorConfiguration("netty",
 URL), ManagementFactory.getPlatformMBeanServer(), new 
ActiveMQJAASSecurityManager(), false));
+
+      final String CUSTOM_GUEST_USER = "foo";
+      ConfigurationImpl.InsertionOrderedProperties props = new 
ConfigurationImpl.InsertionOrderedProperties();
+      props.put("acceptorConfigurations.netty.params.securityDomain", "first");
+      props.put("jaasConfigs.first.modules.guest.loginModuleClass", 
"org.apache.activemq.artemis.spi.core.security.jaas.GuestLoginModule");
+      props.put("jaasConfigs.first.modules.guest.controlFlag", "required");
+      props.put("jaasConfigs.first.modules.guest.params.debug", "true");
+      // these need surround because the login module param keys have dots
+      props.put("jaasConfigs.first.modules.guest.params.\"" + 
GuestLoginModule.GUEST_USER + "\"", CUSTOM_GUEST_USER);
+
+      
server.getConfiguration().parsePrefixedProperties(server.getConfiguration(), 
"test", props, "");
+      assertEquals(2, 
server.getConfiguration().getStatus().split(":\\[\\]").length);
+
+      final Stack<Subject> subjects = new Stack<>();
+      server.getBrokerSessionPlugins().add(new ActiveMQServerSessionPlugin() {
+         @Override
+         public void beforeCreateSession(String name, String username, int 
minLargeMessageSize, RemotingConnection connection, boolean autoCommitSends, 
boolean autoCommitAcks, boolean preAcknowledge, boolean xa, String 
defaultAddress, SessionCallback callback, boolean autoCreateQueues, 
OperationContext context, Map<SimpleString, RoutingType> prefixes) throws 
ActiveMQException {
+            subjects.add(connection.getSubject());
+         }
+      });
+      server.start();
+      
assertTrue(server.getConfiguration().getJaasConfigs().get("first").getModules().get(0).getParams().containsKey(GuestLoginModule.GUEST_USER));
+      try (Connection c = cf.createConnection("first", "secret")) {
+         try (Session s = c.createSession(false, 1)) {
+            Thread.sleep(200);
+         }
+      } catch (JMSException e) {
+         fail("should not throw exception but " + e);
+      }
+
+      Assertions.assertFalse(subjects.empty());
+      Subject subject = subjects.pop();
+      
assertTrue(subject.getPrincipals(UserPrincipal.class).stream().findFirst().isPresent());
+      
assertTrue(subject.getPrincipals(UserPrincipal.class).stream().findFirst().get().getName().equals(CUSTOM_GUEST_USER));
+   }
+
+   @Test
+   public void testJAASSecurityManagerRealmFromIncorrectConfig() throws 
Exception {
+      ActiveMQServer server = 
addServer(ActiveMQServers.newActiveMQServer(createDefaultInVMConfig().setSecurityEnabled(true).setResolveProtocols(true).addAcceptorConfiguration("netty",
 URL + "?securityDomain=first"), ManagementFactory.getPlatformMBeanServer(), 
new ActiveMQJAASSecurityManager(), false));
+
+      ConfigurationImpl.InsertionOrderedProperties props = new 
ConfigurationImpl.InsertionOrderedProperties();
+      // no login module class configured
+      props.put("jaasConfigs.first.modules.guest.controlFlag", "required");
+
+      
server.getConfiguration().parsePrefixedProperties(server.getConfiguration(), 
"test", props, "");
+      assertEquals(2, 
server.getConfiguration().getStatus().split(":\\[\\]").length);
+
+      server.start();
+      try (Connection c = cf.createConnection("first", "secret")) {
+         try (Session s = c.createSession(false, 1)) {
+            // no op
+         }
+         fail("should throw exception here");
+      } catch (JMSSecurityException expected) {
       }
    }
 
diff --git 
a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/server/ConfigurationTest.java
 
b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/server/ConfigurationTest.java
index 7f4dd0c7e3..329f2cf506 100644
--- 
a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/server/ConfigurationTest.java
+++ 
b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/server/ConfigurationTest.java
@@ -107,6 +107,7 @@ public class ConfigurationTest extends ActiveMQTestBase {
       
config.put("addressConfigurations.mytopic_4.queueConfigs.\"queue.B4\".routingType",
 "MULTICAST");
 
       config.put("status", "{\"generation\": \"1\"}");
+      config.put("jaasConfigs.artemisRealm.modules.guest.controlFlag", 
"optional");
 
       try (FileOutputStream outStream = new FileOutputStream(propsFile)) {
          config.store(outStream, null);
@@ -127,6 +128,9 @@ public class ConfigurationTest extends ActiveMQTestBase {
          Bindings mytopic_3 = 
server.getPostOffice().getBindingsForAddress(SimpleString.of("mytopic_3"));
          assertEquals(2, mytopic_3.getBindings().size());
 
+         assertEquals(1, server.getConfiguration().getJaasConfigs().size());
+         config.remove("jaasConfigs.artemisRealm.modules.guest.controlFlag");
+         config.put("jaasConfigs.artemisRealm", "-");
          Bindings myqueue_1 = 
server.getPostOffice().getBindingsForAddress(SimpleString.of("myqueue_1"));
          assertEquals(1, myqueue_1.getBindings().size());
 
@@ -148,6 +152,8 @@ public class ConfigurationTest extends ActiveMQTestBase {
             Bindings mytopic_31 = 
server.getPostOffice().getBindingsForAddress(SimpleString.of("mytopic_3"));
             return mytopic_31.getBindings().size() == 3;
          });
+         // verify empty errors in the status json
+         assertEquals(3, 
server.getConfiguration().getStatus().split(":\\[\\]").length, 
server.getConfiguration().getStatus());
 
          // verify round trip apply
          
assertTrue(server.getActiveMQServerControl().getStatus().contains("2"));
@@ -156,6 +162,8 @@ public class ConfigurationTest extends ActiveMQTestBase {
          
assertTrue(server.getActiveMQServerControl().getStatus().contains("version"));
          
assertTrue(server.getActiveMQServerControl().getStatus().contains("uptime"));
 
+         assertEquals(0, server.getConfiguration().getJaasConfigs().size());
+
       } finally {
          try {
             server.stop();


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

Reply via email to