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