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]