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

clebertsuconic pushed a commit to branch 2.25.x
in repository https://gitbox.apache.org/repos/asf/activemq-artemis.git


The following commit(s) were added to refs/heads/2.25.x by this push:
     new 98003414b8 ARTEMIS-3984 LegacyLDAPSecuritySettingPlugin shouldn't 
modify existing matches
98003414b8 is described below

commit 98003414b81cb25fe48b2a9bf6957639f5918f69
Author: Justin Bertram <[email protected]>
AuthorDate: Sat Sep 10 00:09:37 2022 -0500

    ARTEMIS-3984 LegacyLDAPSecuritySettingPlugin shouldn't modify existing 
matches
    
    When the LegacyLDAPSecuritySettingPlugin has enableListener set to true
    and a new permission is added it will try to modify the existing match
    if one exists. This is problematic if there's a more generic wildcard
    match than the specific one that's modified.
    
    This commit fixes that problem so that instead of modifying the existing
    match(es) it simply adds a new one. The plugin never should have tried
    modifying the existing match in the first place as two identical matches
    would be a configuration error.
    
    (cherry picked from commit a9a85f98db4f49d633541069ae997b4d099837e3)
---
 .../impl/LegacyLDAPSecuritySettingPlugin.java      |  13 +-
 artemis-website/package-lock.json                  |   4 +-
 ...gacyLDAPSecuritySettingPluginListenerTest2.java | 241 +++++++++++++++++++++
 .../src/test/resources/AMQauth3.ldif               | 113 ++++++++++
 .../src/test/resources/login.config                |  21 ++
 5 files changed, 379 insertions(+), 13 deletions(-)

diff --git 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/LegacyLDAPSecuritySettingPlugin.java
 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/LegacyLDAPSecuritySettingPlugin.java
index d3b22bc684..9e8f6df7b8 100644
--- 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/LegacyLDAPSecuritySettingPlugin.java
+++ 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/LegacyLDAPSecuritySettingPlugin.java
@@ -476,17 +476,8 @@ public class LegacyLDAPSecuritySettingPlugin implements 
SecuritySettingPlugin {
       try {
          processSearchResult(newRoles, (SearchResult) 
namingEvent.getNewBinding());
          for (Map.Entry<String, Set<Role>> entry : newRoles.entrySet()) {
-            Set<Role> existingRoles = 
securityRepository.getMatch(entry.getKey());
-            // see if this the *actual* default object, not just "equals"; we 
don't want to change the default security match
-            if (existingRoles != securityRepository.getDefault()) {
-               for (Role role : entry.getValue()) {
-                  logger.debug("adding role " + role + " to existing roles " + 
existingRoles + " at " + entry.getKey());
-                  existingRoles.add(role);
-               }
-            } else {
-               logger.debug("adding new roles " + entry.getValue() + " at " + 
entry.getKey());
-               securityRepository.addMatch(entry.getKey(), entry.getValue());
-            }
+            logger.debug("adding match " + entry.getKey() + ": " + 
entry.getValue());
+            securityRepository.addMatch(entry.getKey(), entry.getValue());
          }
       } catch (NamingException e) {
          ActiveMQServerLogger.LOGGER.failedToProcessEvent(e);
diff --git a/artemis-website/package-lock.json 
b/artemis-website/package-lock.json
index 51ea6670d3..1e5b81dd37 100644
--- a/artemis-website/package-lock.json
+++ b/artemis-website/package-lock.json
@@ -1,11 +1,11 @@
 {
-  "name": "artemis-websiteb",
+  "name": "artemis-website",
   "version": "1.5.1",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
-      "name": "artemis-websiteb",
+      "name": "artemis-website",
       "version": "1.5.1",
       "license": "Apache-2.0",
       "devDependencies": {
diff --git 
a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/LegacyLDAPSecuritySettingPluginListenerTest2.java
 
b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/LegacyLDAPSecuritySettingPluginListenerTest2.java
new file mode 100644
index 0000000000..a486403ef9
--- /dev/null
+++ 
b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/LegacyLDAPSecuritySettingPluginListenerTest2.java
@@ -0,0 +1,241 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.activemq.artemis.tests.integration.security;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.BasicAttribute;
+import javax.naming.directory.BasicAttributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.InitialDirContext;
+import java.io.File;
+import java.lang.management.ManagementFactory;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.apache.activemq.artemis.api.core.ActiveMQException;
+import org.apache.activemq.artemis.api.core.TransportConfiguration;
+import org.apache.activemq.artemis.api.core.client.ActiveMQClient;
+import org.apache.activemq.artemis.api.core.client.ClientProducer;
+import org.apache.activemq.artemis.api.core.client.ClientSession;
+import org.apache.activemq.artemis.api.core.client.ClientSessionFactory;
+import org.apache.activemq.artemis.api.core.client.ServerLocator;
+import org.apache.activemq.artemis.core.config.Configuration;
+import org.apache.activemq.artemis.core.config.WildcardConfiguration;
+import org.apache.activemq.artemis.core.config.impl.ConfigurationImpl;
+import org.apache.activemq.artemis.core.remoting.impl.invm.InVMAcceptorFactory;
+import 
org.apache.activemq.artemis.core.remoting.impl.invm.InVMConnectorFactory;
+import org.apache.activemq.artemis.core.server.ActiveMQServer;
+import org.apache.activemq.artemis.core.server.ActiveMQServers;
+import 
org.apache.activemq.artemis.core.server.impl.LegacyLDAPSecuritySettingPlugin;
+import 
org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager;
+import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
+import org.apache.directory.server.annotations.CreateLdapServer;
+import org.apache.directory.server.annotations.CreateTransport;
+import org.apache.directory.server.core.annotations.ApplyLdifFiles;
+import org.apache.directory.server.core.annotations.CreateDS;
+import org.apache.directory.server.core.annotations.CreatePartition;
+import org.apache.directory.server.core.integ.AbstractLdapTestUnit;
+import org.apache.directory.server.core.integ.FrameworkRunner;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+
+@RunWith(FrameworkRunner.class)
+@CreateDS(name = "myDS",
+   partitions = {
+      @CreatePartition(name = "test", suffix = "dc=example,dc=com")
+   })
+@CreateLdapServer(transports = {@CreateTransport(protocol = "LDAP", port = 
1024)})
+@ApplyLdifFiles("AMQauth3.ldif")
+public class LegacyLDAPSecuritySettingPluginListenerTest2 extends 
AbstractLdapTestUnit {
+
+   static {
+      String path = System.getProperty("java.security.auth.login.config");
+      if (path == null) {
+         URL resource = 
LegacyLDAPSecuritySettingPluginListenerTest2.class.getClassLoader().getResource("login.config");
+         if (resource != null) {
+            path = resource.getFile();
+            System.setProperty("java.security.auth.login.config", path);
+         }
+      }
+   }
+
+   private ServerLocator locator;
+   ActiveMQServer server;
+
+   public static final String TARGET_TMP = "./target/tmp";
+   private static final String PRINCIPAL = "uid=admin,ou=system";
+   private static final String CREDENTIALS = "secret";
+
+   public LegacyLDAPSecuritySettingPluginListenerTest2() {
+      File parent = new File(TARGET_TMP);
+      parent.mkdirs();
+      temporaryFolder = new TemporaryFolder(parent);
+   }
+
+   @Rule
+   public TemporaryFolder temporaryFolder;
+   private String testDir;
+
+   @Before
+   public void setUp() throws Exception {
+      locator = ActiveMQClient.createServerLocatorWithoutHA(new 
TransportConfiguration(InVMConnectorFactory.class.getCanonicalName()));
+      testDir = temporaryFolder.getRoot().getAbsolutePath();
+
+      LegacyLDAPSecuritySettingPlugin legacyLDAPSecuritySettingPlugin = new 
LegacyLDAPSecuritySettingPlugin();
+      Map<String, String> map = new HashMap<>();
+      map.put(LegacyLDAPSecuritySettingPlugin.INITIAL_CONTEXT_FACTORY, 
"com.sun.jndi.ldap.LdapCtxFactory");
+      map.put(LegacyLDAPSecuritySettingPlugin.CONNECTION_URL, 
"ldap://localhost:1024";);
+      map.put(LegacyLDAPSecuritySettingPlugin.CONNECTION_USERNAME, 
"uid=admin,ou=system");
+      map.put(LegacyLDAPSecuritySettingPlugin.CONNECTION_PASSWORD, "secret");
+      map.put(LegacyLDAPSecuritySettingPlugin.CONNECTION_PROTOCOL, "s");
+      map.put(LegacyLDAPSecuritySettingPlugin.AUTHENTICATION, "simple");
+      map.put(LegacyLDAPSecuritySettingPlugin.ENABLE_LISTENER, "true");
+      map.put(LegacyLDAPSecuritySettingPlugin.DESTINATION_BASE, 
"ou=destinations,ou=ActiveMQ,dc=example,dc=com");
+      map.put(LegacyLDAPSecuritySettingPlugin.MAP_ADMIN_TO_MANAGE, "true");
+      legacyLDAPSecuritySettingPlugin.init(map);
+
+      ActiveMQJAASSecurityManager securityManager = new 
ActiveMQJAASSecurityManager("LDAPLogin3");
+      WildcardConfiguration wildcardConfiguration = new 
WildcardConfiguration();
+      wildcardConfiguration.setAnyWords('$');
+      Configuration configuration = new 
ConfigurationImpl().setSecurityEnabled(true).addAcceptorConfiguration(new 
TransportConfiguration(InVMAcceptorFactory.class.getCanonicalName())).setJournalDirectory(ActiveMQTestBase.getJournalDir(testDir,
 0, false)).setBindingsDirectory(ActiveMQTestBase.getBindingsDir(testDir, 0, 
false)).setPagingDirectory(ActiveMQTestBase.getPageDir(testDir, 0, 
false)).setLargeMessagesDirectory(ActiveMQTestBase.getLargeMessagesDir(testDir, 
0, false)).setPersistence [...]
+
+      server = ActiveMQServers.newActiveMQServer(configuration, 
ManagementFactory.getPlatformMBeanServer(), securityManager, false);
+   }
+
+   @After
+   public void tearDown() throws Exception {
+      locator.close();
+      server.stop();
+   }
+
+   private DirContext getContext() throws NamingException {
+      Hashtable<String, String> env = new Hashtable<>();
+      env.put(Context.PROVIDER_URL, "ldap://localhost:1024";);
+      env.put(Context.INITIAL_CONTEXT_FACTORY, 
"com.sun.jndi.ldap.LdapCtxFactory");
+      env.put(Context.SECURITY_AUTHENTICATION, "simple");
+      env.put(Context.SECURITY_PRINCIPAL, PRINCIPAL);
+      env.put(Context.SECURITY_CREDENTIALS, CREDENTIALS);
+      return new InitialDirContext(env);
+   }
+
+   @Test
+   public void testNewUserAndRoleWithWildcard() throws Exception {
+      server.getConfiguration().setSecurityInvalidationInterval(0);
+      server.start();
+      ClientSessionFactory cf = locator.createSessionFactory();
+
+      // authz should succeed
+      try {
+         ClientSession session = cf.createSession("user1", "secret", false, 
true, true, false, 0);
+         ClientProducer producer = session.createProducer("project1.test");
+         producer.send(session.createMessage(true));
+      } catch (ActiveMQException e) {
+         e.printStackTrace();
+         Assert.fail("Should NOT fail");
+      }
+
+      // authz should fail
+      try {
+         ClientSession session = cf.createSession("user1", "secret", false, 
true, true, false, 0);
+         ClientProducer producer = session.createProducer("project2.test");
+         producer.send(session.createMessage(true));
+         Assert.fail("Sending message here should fail!");
+      } catch (ActiveMQException e) {
+         Assert.assertTrue(e.getMessage().contains("229032")); // 
authorization exception
+      }
+
+      { // add new user - user3
+         DirContext ctx = getContext();
+         BasicAttributes basicAttributes = new BasicAttributes();
+         basicAttributes.put("userPassword", "secret");
+         Attribute objclass = new BasicAttribute("objectclass");
+         objclass.add("top");
+         objclass.add("person");
+         objclass.add("organizationalPerson");
+         objclass.add("inetOrgPerson");
+         basicAttributes.put(objclass);
+         Attribute cn = new BasicAttribute("cn");
+         cn.add("user3");
+         basicAttributes.put(cn);
+         Attribute sn = new BasicAttribute("sn");
+         sn.add("user3");
+         basicAttributes.put(sn);
+         ctx.bind("uid=user3,ou=users,dc=example,dc=com", null, 
basicAttributes);
+      }
+
+      { // add new role - team3
+         DirContext ctx = getContext();
+         BasicAttributes basicAttributes = new BasicAttributes();
+         basicAttributes.put("uniqueMember", 
"uid=user3,ou=users,dc=example,dc=com");
+         Attribute objclass = new BasicAttribute("objectclass");
+         objclass.add("top");
+         objclass.add("groupOfUniqueNames");
+         basicAttributes.put(objclass);
+         ctx.bind("cn=team3,ou=roles,dc=example,dc=com", null, 
basicAttributes);
+      }
+
+      { // add new security match - project3.$
+         DirContext ctx = getContext();
+         BasicAttributes basicAttributes = new BasicAttributes();
+         Attribute objclass = new BasicAttribute("objectclass");
+         objclass.add("top");
+         objclass.add("applicationProcess");
+         basicAttributes.put(objclass);
+         
ctx.bind("cn=project3.$,ou=queues,ou=destinations,ou=ActiveMQ,dc=example,dc=com",
 null, basicAttributes);
+      }
+
+      { // add write permission for match
+         DirContext ctx = getContext();
+         BasicAttributes basicAttributes = new BasicAttributes();
+         basicAttributes.put("uniquemember", 
"cn=team3,ou=roles,dc=example,dc=com");
+         Attribute objclass = new BasicAttribute("objectclass");
+         objclass.add("top");
+         objclass.add("groupOfUniqueNames");
+         basicAttributes.put(objclass);
+         
ctx.bind("cn=write,cn=project3.$,ou=queues,ou=destinations,ou=ActiveMQ,dc=example,dc=com",
 null, basicAttributes);
+      }
+
+      // authz should succeed
+      try {
+         ClientSession session = cf.createSession("user3", "secret", false, 
true, true, false, 0);
+         ClientProducer producer = session.createProducer("project3.test");
+         producer.send(session.createMessage(true));
+      } catch (ActiveMQException e) {
+         e.printStackTrace();
+         Assert.fail("Should NOT fail");
+      }
+
+      // authz should fail
+      try {
+         ClientSession session = cf.createSession("user3", "secret", false, 
true, true, false, 0);
+         ClientProducer producer = session.createProducer("project7.test");
+         producer.send(session.createMessage(true));
+         Assert.fail("Sending message here should fail!");
+      } catch (ActiveMQException e) {
+         Assert.assertTrue(e.getMessage().contains("229032")); // 
authorization exception
+      }
+   }
+}
diff --git a/tests/integration-tests/src/test/resources/AMQauth3.ldif 
b/tests/integration-tests/src/test/resources/AMQauth3.ldif
new file mode 100755
index 0000000000..d5997ce645
--- /dev/null
+++ b/tests/integration-tests/src/test/resources/AMQauth3.ldif
@@ -0,0 +1,113 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+
+dn: dc=example,dc=com
+dc: example
+objectclass: domain
+objectclass: top
+
+dn: ou=users,dc=example,dc=com
+objectclass: organizationalUnit
+objectclass: top
+ou: users
+
+dn: uid=user1,ou=users,dc=example,dc=com
+objectClass: inetOrgPerson
+objectClass: organizationalPerson
+objectClass: person
+objectClass: top
+cn: user1
+sn: user1
+givenName: user1
+uid: user1
+userPassword: secret
+
+dn: uid=user2,ou=users,dc=example,dc=com
+objectClass: inetOrgPerson
+objectClass: organizationalPerson
+objectClass: person
+objectClass: top
+cn: user2
+sn: user2
+givenName: user2
+uid: user2
+userPassword: secret
+
+dn: ou=roles,dc=example,dc=com
+objectclass: organizationalUnit
+objectclass: top
+ou: roles
+
+dn: cn=team1,ou=roles,dc=example,dc=com
+objectClass: groupOfUniqueNames
+objectClass: top
+cn: team1
+uniqueMember: uid=user1,ou=users,dc=example,dc=com
+
+dn: cn=team2,ou=roles,dc=example,dc=com
+objectClass: groupOfUniqueNames
+objectClass: top
+cn: team2
+uniqueMember: uid=user2,ou=users,dc=example,dc=com
+
+dn: ou=ActiveMQ,dc=example,dc=com
+objectClass: organizationalUnit
+objectClass: top
+ou: ActiveMQ
+
+dn: ou=destinations,ou=ActiveMQ,dc=example,dc=com
+objectClass: organizationalUnit
+objectClass: top
+ou: destinations
+
+dn: ou=queues,ou=destinations,ou=ActiveMQ,dc=example,dc=com
+objectClass: organizationalUnit
+objectClass: top
+ou: queues
+
+dn: cn=project1.$,ou=queues,ou=destinations,ou=ActiveMQ,dc=example,dc=com
+objectClass: applicationProcess
+objectClass: top
+cn: project1.$
+
+dn: 
cn=write,cn=project1.$,ou=queues,ou=destinations,ou=ActiveMQ,dc=example,dc=com
+objectClass: top
+objectClass: groupOfUniqueNames
+cn: write
+uniqueMember: cn=team1,ou=roles,dc=example,dc=com
+
+dn: cn=project2.$,ou=queues,ou=destinations,ou=ActiveMQ,dc=example,dc=com
+objectClass: applicationProcess
+objectClass: top
+cn: project2.$
+
+dn: 
cn=read,cn=project2.$,ou=queues,ou=destinations,ou=ActiveMQ,dc=example,dc=com
+objectClass: groupOfUniqueNames
+objectClass: top
+cn: read
+uniqueMember: cn=team2,ou=roles,dc=example,dc=com
+
+dn: cn=$,ou=queues,ou=destinations,ou=ActiveMQ,dc=example,dc=com
+objectClass: top
+objectClass: applicationProcess
+cn: $
+
+dn: cn=write,cn=$,ou=queues,ou=destinations,ou=ActiveMQ,dc=example,dc=com
+objectClass: top
+objectClass: groupOfUniqueNames
+cn: write
+uniqueMember: cn=some_role,ou=roles,dc=example,dc=com
diff --git a/tests/integration-tests/src/test/resources/login.config 
b/tests/integration-tests/src/test/resources/login.config
index f1fe8dfaba..a9eaff49a8 100644
--- a/tests/integration-tests/src/test/resources/login.config
+++ b/tests/integration-tests/src/test/resources/login.config
@@ -107,6 +107,27 @@ ExpandedLDAPLogin {
         ;
 };
 
+LDAPLogin3 {
+    org.apache.activemq.artemis.spi.core.security.jaas.LDAPLoginModule required
+        debug=true
+        initialContextFactory=com.sun.jndi.ldap.LdapCtxFactory
+        connectionURL="ldap://localhost:1024";
+        connectionUsername="uid=admin,ou=system"
+        connectionPassword=secret
+        connectionProtocol=s
+        authentication=simple
+        userBase="ou=users,dc=example,dc=com"
+        userSearchMatching="(uid={0})"
+        userSearchSubtree=true
+        roleBase="ou=roles,dc=example,dc=com"
+        roleName=cn
+        roleSearchMatching="(uniqueMember={0})"
+        roleSearchSubtree=true
+        connectionPool=true
+        connectionTimeout="5000"
+        ;
+};
+
 GuestLogin {
     org.apache.activemq.artemis.spi.core.security.jaas.GuestLoginModule 
required
         debug=true

Reply via email to