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

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


The following commit(s) were added to refs/heads/master by this push:
     new 9a90248  ARTEMIS-2889 better support for JMS topics with legacy LDAP 
plugin
     new b71bfcc  This closes #3248
9a90248 is described below

commit 9a90248f49480717dd7a8de69c566afa6fe4cbaa
Author: Justin Bertram <[email protected]>
AuthorDate: Fri Aug 28 21:41:53 2020 -0500

    ARTEMIS-2889 better support for JMS topics with legacy LDAP plugin
---
 .../impl/LegacyLDAPSecuritySettingPlugin.java      | 36 +++++++++++++------
 docs/user-manual/en/security.md                    |  6 ++++
 .../LegacyLDAPSecuritySettingPluginTest.java       | 41 ++++++++++++++++++++++
 .../src/test/resources/AMQauth.ldif                | 29 +++++++++++++++
 4 files changed, 101 insertions(+), 11 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 d9d61ad..d3b22bc 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
@@ -66,6 +66,7 @@ public class LegacyLDAPSecuritySettingPlugin implements 
SecuritySettingPlugin {
    public static final String WRITE_PERMISSION_VALUE = "writePermissionValue";
    public static final String ENABLE_LISTENER = "enableListener";
    public static final String MAP_ADMIN_TO_MANAGE = "mapAdminToManage";
+   public static final String ALLOW_QUEUE_ADMIN_ON_READ = 
"allowQueueAdminOnRead";
 
    private String initialContextFactory = "com.sun.jndi.ldap.LdapCtxFactory";
    private String connectionURL = "ldap://localhost:1024";;
@@ -81,6 +82,7 @@ public class LegacyLDAPSecuritySettingPlugin implements 
SecuritySettingPlugin {
    private String writePermissionValue = "write";
    private boolean enableListener = true;
    private boolean mapAdminToManage = false;
+   private boolean allowQueueAdminOnRead = false;
 
    private DirContext context;
    private EventDirContext eventContext;
@@ -104,6 +106,7 @@ public class LegacyLDAPSecuritySettingPlugin implements 
SecuritySettingPlugin {
          writePermissionValue = getOption(options, WRITE_PERMISSION_VALUE, 
writePermissionValue);
          enableListener = getOption(options, ENABLE_LISTENER, 
Boolean.TRUE.toString()).equalsIgnoreCase(Boolean.TRUE.toString());
          mapAdminToManage = getOption(options, MAP_ADMIN_TO_MANAGE, 
Boolean.FALSE.toString()).equalsIgnoreCase(Boolean.TRUE.toString());
+         allowQueueAdminOnRead = getOption(options, ALLOW_QUEUE_ADMIN_ON_READ, 
Boolean.FALSE.toString()).equalsIgnoreCase(Boolean.TRUE.toString());
       }
 
       return this;
@@ -244,6 +247,15 @@ public class LegacyLDAPSecuritySettingPlugin implements 
SecuritySettingPlugin {
       return this;
    }
 
+   public boolean isAllowQueueAdminOnRead() {
+      return allowQueueAdminOnRead;
+   }
+
+   public LegacyLDAPSecuritySettingPlugin setAllowQueueAdminOnRead(boolean 
allowQueueAdminOnRead) {
+      this.allowQueueAdminOnRead = allowQueueAdminOnRead;
+      return this;
+   }
+
    protected boolean isContextAlive() {
       boolean alive = false;
       if (context != null) {
@@ -405,18 +417,20 @@ public class LegacyLDAPSecuritySettingPlugin implements 
SecuritySettingPlugin {
          if (logger.isDebugEnabled()) {
             logMessage.append("\n\tRole name: ").append(roleName);
          }
+         boolean write = permissionType.equalsIgnoreCase(writePermissionValue);
+         boolean read = permissionType.equalsIgnoreCase(readPermissionValue);
+         boolean admin = permissionType.equalsIgnoreCase(adminPermissionValue);
          Role role = new Role(roleName,
-                              
permissionType.equalsIgnoreCase(writePermissionValue), // send
-                              
permissionType.equalsIgnoreCase(readPermissionValue),  // consume
-                              
permissionType.equalsIgnoreCase(adminPermissionValue), // createDurableQueue
-                              
permissionType.equalsIgnoreCase(adminPermissionValue), // deleteDurableQueue
-                              
permissionType.equalsIgnoreCase(adminPermissionValue), // createNonDurableQueue
-                              
permissionType.equalsIgnoreCase(adminPermissionValue), // deleteNonDurableQueue
-                              mapAdminToManage ? 
permissionType.equalsIgnoreCase(adminPermissionValue) : false, // manage - map 
to admin based on configuration
-                              
permissionType.equalsIgnoreCase(readPermissionValue),  // browse
-                              
permissionType.equalsIgnoreCase(adminPermissionValue), // createAddress
-                              
permissionType.equalsIgnoreCase(adminPermissionValue)  // deleteAddress
-                              );
+                              write,                                     // 
send
+                              read,                                      // 
consume
+                              (allowQueueAdminOnRead && read) || admin,  // 
createDurableQueue
+                              (allowQueueAdminOnRead && read) || admin,  // 
deleteDurableQueue
+                              (allowQueueAdminOnRead && read) || admin,  // 
createNonDurableQueue
+                              admin,                                     // 
deleteNonDurableQueue
+                              mapAdminToManage ? admin : false,          // 
manage - map to admin based on configuration
+                              read,                                      // 
browse
+                              admin,                                     // 
createAddress
+                              admin);                                    // 
deleteAddress
          roles.add(role);
       }
 
diff --git a/docs/user-manual/en/security.md b/docs/user-manual/en/security.md
index 41fb770..43d47a7 100644
--- a/docs/user-manual/en/security.md
+++ b/docs/user-manual/en/security.md
@@ -300,6 +300,12 @@ and Security Layer (SASL) authentication is currently not 
supported.
   `manage` permission. See details of the mapping semantics below. The default
    value is `false`.
 
+- `allowQueueAdminOnRead`. Whether or not to map the legacy `read` permission 
to
+  the `createDurableQueue`, `createNonDurableQueue`, and `deleteDurableQueue`
+  permissions so that JMS clients can create durable and non-durable 
subscriptions
+  without needing the `admin` permission. This was allowed in ActiveMQ 5.x. The
+  default value is `false`.
+
 The name of the queue or topic defined in LDAP will serve as the "match" for
 the security-setting, the permission value will be mapped from the ActiveMQ 5.x
 type to the Artemis type, and the role will be mapped as-is.
diff --git 
a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/LegacyLDAPSecuritySettingPluginTest.java
 
b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/LegacyLDAPSecuritySettingPluginTest.java
index 0401c93..89ba895 100644
--- 
a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/LegacyLDAPSecuritySettingPluginTest.java
+++ 
b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/LegacyLDAPSecuritySettingPluginTest.java
@@ -16,6 +16,11 @@
  */
 package org.apache.activemq.artemis.tests.integration.security;
 
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.MessageConsumer;
+import javax.jms.Session;
+import javax.jms.Topic;
 import javax.naming.Context;
 import javax.naming.NameClassPair;
 import javax.naming.NamingEnumeration;
@@ -44,7 +49,9 @@ 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.api.core.RoutingType;
+import org.apache.activemq.artemis.core.server.impl.AddressInfo;
 import 
org.apache.activemq.artemis.core.server.impl.LegacyLDAPSecuritySettingPlugin;
+import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
 import 
org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager;
 import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
 import org.apache.directory.server.annotations.CreateLdapServer;
@@ -320,4 +327,38 @@ public class LegacyLDAPSecuritySettingPluginTest extends 
AbstractLdapTestUnit {
       session.close();
       cf.close();
    }
+
+   @Test
+   public void testJmsTopicSubscriberReadPermissionOnly() throws Exception {
+      internalJmsTopicSubscriberReadPermissionOnly(false);
+   }
+
+   @Test
+   public void testJmsTopicDurableSubscriberReadPermissionOnly() throws 
Exception {
+      internalJmsTopicSubscriberReadPermissionOnly(true);
+   }
+
+   private void internalJmsTopicSubscriberReadPermissionOnly(boolean durable) 
throws Exception {
+      
((LegacyLDAPSecuritySettingPlugin)server.getConfiguration().getSecuritySettingPlugins().get(0)).setAllowQueueAdminOnRead(true);
+      server.start();
+
+      // The address needs to exist already otherwise the "admin" permission 
is required to create it
+      server.addAddressInfo(new 
AddressInfo(SimpleString.toSimpleString("topic1"), RoutingType.MULTICAST));
+
+      ConnectionFactory cf = new ActiveMQConnectionFactory("vm://0");
+      try (Connection connection = cf.createConnection("third", "secret")) {
+         Session session = connection.createSession();
+         Topic topic = session.createTopic("topic1");
+         if (durable) {
+            MessageConsumer consumer = 
session.createSharedDurableConsumer(topic, "foo");
+            consumer.close();
+            session.unsubscribe("foo");
+         } else {
+            session.createConsumer(topic);
+         }
+      } catch (Exception e) {
+         e.printStackTrace();
+         Assert.fail("should not throw exception here");
+      }
+   }
 }
diff --git a/tests/integration-tests/src/test/resources/AMQauth.ldif 
b/tests/integration-tests/src/test/resources/AMQauth.ldif
index 12ba199..74f04f7 100755
--- a/tests/integration-tests/src/test/resources/AMQauth.ldif
+++ b/tests/integration-tests/src/test/resources/AMQauth.ldif
@@ -39,6 +39,13 @@ objectClass: account
 objectClass: simpleSecurityObject
 objectClass: top
 
+dn: uid=third,ou=system
+uid: third
+userPassword: secret
+objectClass: account
+objectClass: simpleSecurityObject
+objectClass: top
+
 dn: cn=role1,ou=system
 cn: role1
 member: uid=first,ou=system
@@ -51,6 +58,12 @@ member: uid=second,ou=system
 objectClass: groupOfNames
 objectClass: top
 
+dn: cn=role3,ou=system
+cn: role3
+member: uid=third,ou=system
+objectClass: groupOfNames
+objectClass: top
+
 dn: ou=destinations,o=ActiveMQ,ou=system
 objectclass: organizationalUnit
 objectclass: top
@@ -61,6 +74,11 @@ objectclass: organizationalUnit
 objectclass: top
 ou: queues
 
+dn: ou=topics,ou=destinations,o=ActiveMQ,ou=system
+objectclass: organizationalUnit
+objectclass: top
+ou: topics
+
 dn: cn=queue1,ou=queues,ou=destinations,o=ActiveMQ,ou=system
 objectclass: applicationProcess
 objectclass: top
@@ -71,6 +89,11 @@ objectclass: applicationProcess
 objectclass: top
 cn: queue2
 
+dn: cn=topic1,ou=topics,ou=destinations,o=ActiveMQ,ou=system
+objectclass: applicationProcess
+objectclass: top
+cn: topic1
+
 dn: cn=activemq.management,ou=queues,ou=destinations,o=ActiveMQ,ou=system
 objectclass: applicationProcess
 objectclass: top
@@ -112,6 +135,12 @@ objectclass: top
 cn: admin
 uniquemember: cn=role1
 
+dn: cn=read,cn=topic1,ou=topics,ou=destinations,o=ActiveMQ,ou=system
+objectclass: groupOfUniqueNames
+objectclass: top
+cn: read
+uniquemember: cn=role3
+
 ## group with member identified just by DN from SASL external tls certificate 
subject DN
 dn: cn=widgets,ou=system
 cn: widgets

Reply via email to