activemq-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From clebertsuco...@apache.org
Subject [2/3] activemq-artemis git commit: ARTEMIS-168 - pluggable authorization
Date Tue, 27 Oct 2015 14:12:39 GMT
ARTEMIS-168 - pluggable authorization


Project: http://git-wip-us.apache.org/repos/asf/activemq-artemis/repo
Commit: http://git-wip-us.apache.org/repos/asf/activemq-artemis/commit/fe4dafed
Tree: http://git-wip-us.apache.org/repos/asf/activemq-artemis/tree/fe4dafed
Diff: http://git-wip-us.apache.org/repos/asf/activemq-artemis/diff/fe4dafed

Branch: refs/heads/master
Commit: fe4dafedcb5daab883694f2eaaedf3ae3dad29b8
Parents: d03541a
Author: jbertram <jbertram@apache.org>
Authored: Fri Oct 9 08:29:41 2015 -0500
Committer: Clebert Suconic <clebertsuconic@apache.org>
Committed: Tue Oct 27 10:12:22 2015 -0400

----------------------------------------------------------------------
 .../artemis/core/config/Configuration.java      |   7 +
 .../core/config/impl/ConfigurationImpl.java     |  20 ++
 .../deployers/impl/FileConfigurationParser.java |  40 +++
 .../core/server/ActiveMQServerLogger.java       |  12 +
 .../core/server/SecuritySettingPlugin.java      |  57 ++++
 .../impl/LegacyLDAPSecuritySettingPlugin.java   | 321 +++++++++++++++++++
 .../resources/schema/artemis-configuration.xsd  |  36 +++
 .../core/config/impl/FileConfigurationTest.java |  19 ++
 .../resources/ConfigurationTest-full-config.xml |  14 +
 docs/user-manual/en/security.md                 | 115 +++++++
 .../LegacyLDAPSecuritySettingPluginTest.java    | 317 ++++++++++++++++++
 .../src/test/resources/AMQauth.ldif             |  94 ++++++
 12 files changed, 1052 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/fe4dafed/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/Configuration.java
----------------------------------------------------------------------
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 529f6cf..8d5832f 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
@@ -27,6 +27,7 @@ import org.apache.activemq.artemis.api.core.SimpleString;
 import org.apache.activemq.artemis.api.core.TransportConfiguration;
 import org.apache.activemq.artemis.core.security.Role;
 import org.apache.activemq.artemis.core.server.JournalType;
+import org.apache.activemq.artemis.core.server.SecuritySettingPlugin;
 import org.apache.activemq.artemis.core.server.group.impl.GroupingHandlerConfiguration;
 import org.apache.activemq.artemis.core.settings.impl.AddressSettings;
 import org.apache.activemq.artemis.core.settings.impl.ResourceLimitSettings;
@@ -852,11 +853,17 @@ public interface Configuration {
 
    Configuration addConnectorServiceConfiguration(ConnectorServiceConfiguration config);
 
+   Configuration setSecuritySettingPlugins(final List<SecuritySettingPlugin> plugins);
+
+   Configuration addSecuritySettingPlugin(final SecuritySettingPlugin plugin);
+
    /**
     * @return list of {@link ConnectorServiceConfiguration}
     */
    List<ConnectorServiceConfiguration> getConnectorServiceConfigurations();
 
+   List<SecuritySettingPlugin> getSecuritySettingPlugins();
+
    /**
     * The default password decoder
     */

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/fe4dafed/artemis-server/src/main/java/org/apache/activemq/artemis/core/config/impl/ConfigurationImpl.java
----------------------------------------------------------------------
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 b8b4c2d..ae38248 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
@@ -48,6 +48,7 @@ import org.apache.activemq.artemis.core.config.ha.ReplicaPolicyConfiguration;
 import org.apache.activemq.artemis.core.config.ha.ReplicatedPolicyConfiguration;
 import org.apache.activemq.artemis.core.security.Role;
 import org.apache.activemq.artemis.core.server.JournalType;
+import org.apache.activemq.artemis.core.server.SecuritySettingPlugin;
 import org.apache.activemq.artemis.core.server.group.impl.GroupingHandlerConfiguration;
 import org.apache.activemq.artemis.core.settings.impl.AddressSettings;
 import org.apache.activemq.artemis.core.settings.impl.ResourceLimitSettings;
@@ -209,6 +210,8 @@ public class ConfigurationImpl implements Configuration, Serializable {
 
    private Map<String, Set<Role>> securitySettings = new HashMap<String, Set<Role>>();
 
+   private List<SecuritySettingPlugin> securitySettingPlugins = new ArrayList<SecuritySettingPlugin>();
+
    protected List<ConnectorServiceConfiguration> connectorServiceConfigurations = new ArrayList<ConnectorServiceConfiguration>();
 
    private boolean maskPassword = ActiveMQDefaultConfiguration.isDefaultMaskPassword();
@@ -964,6 +967,9 @@ public class ConfigurationImpl implements Configuration, Serializable {
 
    @Override
    public Map<String, Set<Role>> getSecurityRoles() {
+      for (SecuritySettingPlugin securitySettingPlugin : securitySettingPlugins) {
+         securitySettings.putAll(securitySettingPlugin.getSecurityRoles());
+      }
       return securitySettings;
    }
 
@@ -977,6 +983,10 @@ public class ConfigurationImpl implements Configuration, Serializable {
       return this.connectorServiceConfigurations;
    }
 
+   public List<SecuritySettingPlugin> getSecuritySettingPlugins() {
+      return this.securitySettingPlugins;
+   }
+
    public File getBrokerInstance() {
       if (artemisInstance != null) {
          return artemisInstance;
@@ -1036,6 +1046,16 @@ public class ConfigurationImpl implements Configuration, Serializable {
       return this;
    }
 
+   public ConfigurationImpl setSecuritySettingPlugins(final List<SecuritySettingPlugin> plugins) {
+      this.securitySettingPlugins = plugins;
+      return this;
+   }
+
+   public ConfigurationImpl addSecuritySettingPlugin(final SecuritySettingPlugin plugin) {
+      this.securitySettingPlugins.add(plugin);
+      return this;
+   }
+
    public boolean isMaskPassword() {
       return maskPassword;
    }

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/fe4dafed/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java
----------------------------------------------------------------------
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java
index 0e75719..76c3916 100644
--- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java
@@ -19,6 +19,8 @@ package org.apache.activemq.artemis.core.deployers.impl;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.Reader;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -56,6 +58,7 @@ import org.apache.activemq.artemis.core.io.aio.AIOSequentialFileFactory;
 import org.apache.activemq.artemis.core.security.Role;
 import org.apache.activemq.artemis.core.server.ActiveMQServerLogger;
 import org.apache.activemq.artemis.core.server.JournalType;
+import org.apache.activemq.artemis.core.server.SecuritySettingPlugin;
 import org.apache.activemq.artemis.core.server.cluster.impl.MessageLoadBalancingType;
 import org.apache.activemq.artemis.core.server.group.impl.GroupingHandlerConfiguration;
 import org.apache.activemq.artemis.core.settings.impl.AddressFullMessagePolicy;
@@ -64,6 +67,7 @@ import org.apache.activemq.artemis.core.settings.impl.ResourceLimitSettings;
 import org.apache.activemq.artemis.core.settings.impl.SlowConsumerPolicy;
 import org.apache.activemq.artemis.uri.AcceptorTransportConfigurationParser;
 import org.apache.activemq.artemis.uri.ConnectorTransportConfigurationParser;
+import org.apache.activemq.artemis.utils.ClassloadingUtil;
 import org.apache.activemq.artemis.utils.DefaultSensitiveStringCodec;
 import org.apache.activemq.artemis.utils.PasswordMaskingUtil;
 import org.apache.activemq.artemis.utils.SensitiveDataCodec;
@@ -82,12 +86,20 @@ public final class FileConfigurationParser extends XMLConfigurationUtil {
    // Security Parsing
    public static final String SECURITY_ELEMENT_NAME = "security-setting";
 
+   public static final String SECURITY_PLUGIN_ELEMENT_NAME = "security-setting-plugin";
+
    private static final String PERMISSION_ELEMENT_NAME = "permission";
 
+   private static final String SETTING_ELEMENT_NAME = "setting";
+
    private static final String TYPE_ATTR_NAME = "type";
 
    private static final String ROLES_ATTR_NAME = "roles";
 
+   private static final String NAME_ATTR_NAME = "name";
+
+   private static final String VALUE_ATTR_NAME = "value";
+
    static final String CREATEDURABLEQUEUE_NAME = "createDurableQueue";
 
    private static final String DELETEDURABLEQUEUE_NAME = "deleteDurableQueue";
@@ -517,6 +529,11 @@ public final class FileConfigurationParser extends XMLConfigurationUtil {
             Pair<String, Set<Role>> securityItem = parseSecurityRoles(list.item(i));
             config.getSecurityRoles().put(securityItem.getA(), securityItem.getB());
          }
+         list = node.getElementsByTagName(SECURITY_PLUGIN_ELEMENT_NAME);
+         for (int i = 0; i < list.getLength(); i++) {
+            Pair<SecuritySettingPlugin, Map<String, String>> securityItem = parseSecuritySettingPlugins(list.item(i));
+            config.addSecuritySettingPlugin(securityItem.getA().init(securityItem.getB()).populateSecurityRoles());
+         }
       }
    }
 
@@ -643,6 +660,29 @@ public final class FileConfigurationParser extends XMLConfigurationUtil {
       return securityMatch;
    }
 
+   private Pair<SecuritySettingPlugin,Map<String,String>> parseSecuritySettingPlugins(Node item) {
+      final String clazz = item.getAttributes().getNamedItem("class-name").getNodeValue();
+      final Map<String, String> settings = new HashMap<>();
+      NodeList children = item.getChildNodes();
+      for (int j = 0; j < children.getLength(); j++) {
+         Node child = children.item(j);
+         final String nodeName = child.getNodeName();
+         if (SETTING_ELEMENT_NAME.equalsIgnoreCase(nodeName)) {
+            final String settingName = getAttributeValue(child, NAME_ATTR_NAME);
+            final String settingValue = getAttributeValue(child, VALUE_ATTR_NAME);
+            settings.put(settingName, settingValue);
+         }
+      }
+
+      SecuritySettingPlugin securitySettingPlugin = AccessController.doPrivileged(new PrivilegedAction<SecuritySettingPlugin>() {
+         public SecuritySettingPlugin run() {
+            return (SecuritySettingPlugin) ClassloadingUtil.newInstanceFromClassLoader(clazz);
+         }
+      });
+
+      return new Pair<SecuritySettingPlugin, Map<String, String>>(securitySettingPlugin, settings);
+   }
+
    /**
     * @param node
     * @return

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/fe4dafed/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServerLogger.java
----------------------------------------------------------------------
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServerLogger.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServerLogger.java
index d414a9f..aada318 100644
--- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServerLogger.java
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServerLogger.java
@@ -301,6 +301,10 @@ public interface ActiveMQServerLogger extends BasicLogger {
    @Message(id = 221050, value = "Activating Shared Store Slave", format = Message.Format.MESSAGE_FORMAT)
    void activatingSharedStoreSlave();
 
+   @LogMessage(level = Logger.Level.INFO)
+   @Message(id = 221051, value = "Populating security roles from LDAP at: {0}", format = Message.Format.MESSAGE_FORMAT)
+   void populatingSecurityRolesFromLDAP(String url);
+
    @LogMessage(level = Logger.Level.WARN)
    @Message(id = 222000, value = "ActiveMQServer is being finalized and has not been stopped. Please remember to stop the server before letting it go out of scope",
       format = Message.Format.MESSAGE_FORMAT)
@@ -1445,4 +1449,12 @@ public interface ActiveMQServerLogger extends BasicLogger {
    @LogMessage(level = Logger.Level.ERROR)
    @Message(id = 224065, value = "Failed to remove auto-created queue {0}", format = Message.Format.MESSAGE_FORMAT)
    void errorRemovingAutoCreatedQueue(@Cause Exception e, SimpleString bindingName);
+
+   @LogMessage(level = Logger.Level.ERROR)
+   @Message(id = 224066, value = "Error opening context for LDAP", format = Message.Format.MESSAGE_FORMAT)
+   void errorOpeningContextForLDAP(@Cause Exception e);
+
+   @LogMessage(level = Logger.Level.ERROR)
+   @Message(id = 224067, value = "Error populating security roles from LDAP", format = Message.Format.MESSAGE_FORMAT)
+   void errorPopulatingSecurityRolesFromLDAP(@Cause Exception e);
 }

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/fe4dafed/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/SecuritySettingPlugin.java
----------------------------------------------------------------------
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/SecuritySettingPlugin.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/SecuritySettingPlugin.java
new file mode 100644
index 0000000..0803e2f
--- /dev/null
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/SecuritySettingPlugin.java
@@ -0,0 +1,57 @@
+/*
+ * 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.server;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.activemq.artemis.core.security.Role;
+
+public interface SecuritySettingPlugin extends Serializable {
+   /**
+    * Initialize the plugin with the given configuration options. This method is called by the broker when the file-based
+    * configuration is read (see {@code org.apache.activemq.artemis.core.deployers.impl.FileConfigurationParser#parseSecurity(org.w3c.dom.Element, org.apache.activemq.artemis.core.config.Configuration)}.
+    * If you're creating/configuring the plugin programmatically then the recommended approach is to simply use the plugin's
+    * getters/setters rather than this method.
+    *
+    * @param options name/value pairs used to configure the SecuritySettingPlugin instance
+    * @return {@code this} instance
+    */
+   SecuritySettingPlugin init(Map<String, String> options);
+
+   /**
+    * Once {@code #populateSecurityRoles} is invoked this method should return the security role information from the
+    * external environment (e.g. file, LDAP, etc.).
+    *
+    * @return the Map's key corresponds to the "match" for the security setting and the corresponding value is the set of
+    * {@code org.apache.activemq.artemis.core.security.Role} objects defining the appropriate authorization
+    */
+   Map<String, Set<Role>> getSecurityRoles();
+
+   /**
+    * Fetch the security role information from the external environment (e.g. file, LDAP, etc.). This method should put
+    * the security role information in the variable that is returned by {@code #getSecurityRoles()}. This method is
+    * called by the broker when the file-based configuration is read (see {@code org.apache.activemq.artemis.core.deployers.impl.FileConfigurationParser#parseSecurity(org.w3c.dom.Element, org.apache.activemq.artemis.core.config.Configuration)}
+    * so that later when {@code #getSecurityRoles()} is called by {@code org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl#deploySecurity()}
+    * the necessary information will be present. If you're creating/configuring the plugin programmatically then you'll
+    * want to invoke this method soon after instantiating and configuring it.
+    *
+    * @return {@code this} instance
+    */
+   SecuritySettingPlugin populateSecurityRoles();
+}

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/fe4dafed/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/LegacyLDAPSecuritySettingPlugin.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..cc24dd5
--- /dev/null
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/LegacyLDAPSecuritySettingPlugin.java
@@ -0,0 +1,321 @@
+/*
+ * 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.server.impl;
+
+import javax.naming.Context;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.InitialDirContext;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+import javax.naming.ldap.LdapName;
+import javax.naming.ldap.Rdn;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.activemq.artemis.core.security.Role;
+import org.apache.activemq.artemis.core.server.SecuritySettingPlugin;
+import org.apache.activemq.artemis.core.server.ActiveMQServerLogger;
+
+public class LegacyLDAPSecuritySettingPlugin implements SecuritySettingPlugin {
+   private static final long serialVersionUID = 4793109879399750045L;
+
+   public static final String INITIAL_CONTEXT_FACTORY = "initialContextFactory";
+   public static final String CONNECTION_URL = "connectionURL";
+   public static final String CONNECTION_USERNAME = "connectionUsername";
+   public static final String CONNECTION_PASSWORD = "connectionPassword";
+   public static final String CONNECTION_PROTOCOL = "connectionProtocol";
+   public static final String AUTHENTICATION = "authentication";
+   public static final String ROLE_ATTRIBUTE = "roleAttribute";
+   public static final String FILTER = "filter";
+   public static final String DESTINATION_BASE = "destinationBase";
+   public static final String ADMIN_PERMISSION_VALUE = "adminPermissionValue";
+   public static final String READ_PERMISSION_VALUE = "readPermissionValue";
+   public static final String WRITE_PERMISSION_VALUE = "writePermissionValue";
+
+   private String initialContextFactory = "com.sun.jndi.ldap.LdapCtxFactory";
+   private String connectionURL = "ldap://localhost:1024";
+   private String connectionUsername;
+   private String connectionPassword;
+   private String connectionProtocol;
+   private String authentication = "simple";
+   private String destinationBase = "ou=destinations,o=ActiveMQ,ou=system";
+   private String filter = "(cn=*)";
+   private String roleAttribute = "uniqueMember";
+   private String adminPermissionValue = "admin";
+   private String readPermissionValue = "read";
+   private String writePermissionValue = "write";
+
+   private DirContext context;
+   private Map<String, Set<Role>> securityRoles = new HashMap<>();
+
+   @Override
+   public LegacyLDAPSecuritySettingPlugin init(Map<String, String> options) {
+      if (options != null) {
+         initialContextFactory = options.get(INITIAL_CONTEXT_FACTORY);
+         connectionURL = options.get(CONNECTION_URL);
+         connectionUsername = options.get(CONNECTION_USERNAME);
+         connectionPassword = options.get(CONNECTION_PASSWORD);
+         connectionProtocol = options.get(CONNECTION_PROTOCOL);
+         authentication = options.get(AUTHENTICATION);
+         destinationBase = options.get(DESTINATION_BASE);
+         filter = options.get(FILTER);
+         roleAttribute = options.get(ROLE_ATTRIBUTE);
+         adminPermissionValue = options.get(ADMIN_PERMISSION_VALUE);
+         readPermissionValue = options.get(READ_PERMISSION_VALUE);
+         writePermissionValue = options.get(WRITE_PERMISSION_VALUE);
+      }
+
+      return this;
+   }
+
+   public String getRoleAttribute() {
+      return roleAttribute;
+   }
+
+   public SecuritySettingPlugin setRoleAttribute(String roleAttribute) {
+      this.roleAttribute = roleAttribute;
+      return this;
+   }
+
+   public String getFilter() {
+      return filter;
+   }
+
+   public LegacyLDAPSecuritySettingPlugin setFilter(String filter) {
+      this.filter = filter;
+      return this;
+   }
+
+   public String getDestinationBase() {
+      return destinationBase;
+   }
+
+   public LegacyLDAPSecuritySettingPlugin setDestinationBase(String destinationBase) {
+      this.destinationBase = destinationBase;
+      return this;
+   }
+
+   public String getAuthentication() {
+      return authentication;
+   }
+
+   public LegacyLDAPSecuritySettingPlugin setAuthentication(String authentication) {
+      this.authentication = authentication;
+      return this;
+   }
+
+   public String getConnectionPassword() {
+      return connectionPassword;
+   }
+
+   public LegacyLDAPSecuritySettingPlugin setConnectionPassword(String connectionPassword) {
+      this.connectionPassword = connectionPassword;
+      return this;
+   }
+
+   public String getConnectionProtocol() {
+      return connectionProtocol;
+   }
+
+   public LegacyLDAPSecuritySettingPlugin setConnectionProtocol(String connectionProtocol) {
+      this.connectionProtocol = connectionProtocol;
+      return this;
+   }
+
+   public String getConnectionURL() {
+      return connectionURL;
+   }
+
+   public LegacyLDAPSecuritySettingPlugin setConnectionURL(String connectionURL) {
+      this.connectionURL = connectionURL;
+      return this;
+   }
+
+   public String getConnectionUsername() {
+      return connectionUsername;
+   }
+
+   public LegacyLDAPSecuritySettingPlugin setConnectionUsername(String connectionUsername) {
+      this.connectionUsername = connectionUsername;
+      return this;
+   }
+
+   public String getInitialContextFactory() {
+      return initialContextFactory;
+   }
+
+   public String getAdminPermissionValue() {
+      return adminPermissionValue;
+   }
+
+   public LegacyLDAPSecuritySettingPlugin setAdminPermissionValue(String adminPermissionValue) {
+      this.adminPermissionValue = adminPermissionValue;
+      return this;
+   }
+
+   public String getReadPermissionValue() {
+      return readPermissionValue;
+   }
+
+   public LegacyLDAPSecuritySettingPlugin setReadPermissionValue(String readPermissionValue) {
+      this.readPermissionValue = readPermissionValue;
+      return this;
+   }
+
+   public String getWritePermissionValue() {
+      return writePermissionValue;
+   }
+
+   public LegacyLDAPSecuritySettingPlugin setWritePermissionValue(String writePermissionValue) {
+      this.writePermissionValue = writePermissionValue;
+      return this;
+   }
+
+   public LegacyLDAPSecuritySettingPlugin setInitialContextFactory(String initialContextFactory) {
+      this.initialContextFactory = initialContextFactory;
+      return this;
+   }
+
+   protected void open() throws NamingException {
+      if (context != null) {
+         return;
+      }
+
+      Hashtable<String, String> env = new Hashtable<String, String>();
+      env.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory);
+      if (connectionUsername != null && !"".equals(connectionUsername)) {
+         env.put(Context.SECURITY_PRINCIPAL, connectionUsername);
+      }
+      else {
+         throw new NamingException("Empty username is not allowed");
+      }
+      if (connectionPassword != null && !"".equals(connectionPassword)) {
+         env.put(Context.SECURITY_CREDENTIALS, connectionPassword);
+      }
+      else {
+         throw new NamingException("Empty password is not allowed");
+      }
+      env.put(Context.SECURITY_PROTOCOL, connectionProtocol);
+      env.put(Context.PROVIDER_URL, connectionURL);
+      env.put(Context.SECURITY_AUTHENTICATION, authentication);
+      context = new InitialDirContext(env);
+   }
+
+   @Override
+   public Map<String, Set<Role>> getSecurityRoles() {
+      return securityRoles;
+   }
+
+   @Override
+   public LegacyLDAPSecuritySettingPlugin populateSecurityRoles() {
+      ActiveMQServerLogger.LOGGER.populatingSecurityRolesFromLDAP(connectionURL);
+      try {
+         open();
+      }
+      catch (Exception e) {
+         ActiveMQServerLogger.LOGGER.errorOpeningContextForLDAP(e);
+         return this;
+      }
+
+      SearchControls searchControls = new SearchControls();
+      searchControls.setReturningAttributes(new String[]{roleAttribute});
+      searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
+
+      Map<String, Set<Role>> securityRoles = new HashMap<String, Set<Role>>();
+      try {
+         NamingEnumeration<SearchResult> searchResults = context.search(destinationBase, filter, searchControls);
+         int i = 0;
+         while (searchResults.hasMore()) {
+            SearchResult searchResult = searchResults.next();
+            Attributes attrs = searchResult.getAttributes();
+            if (attrs == null || attrs.size() == 0) {
+               continue;
+            }
+            LdapName searchResultLdapName = new LdapName(searchResult.getName());
+            ActiveMQServerLogger.LOGGER.debug("LDAP search result " + ++i + ": " + searchResultLdapName);
+            String permissionType = null;
+            String destination = null;
+            String destinationType = "unknown";
+            for (Rdn rdn : searchResultLdapName.getRdns()) {
+               if (rdn.getType().equals("cn")) {
+                  ActiveMQServerLogger.LOGGER.debug("\tPermission type: " + rdn.getValue());
+                  permissionType = rdn.getValue().toString();
+               }
+               if (rdn.getType().equals("uid")) {
+                  ActiveMQServerLogger.LOGGER.debug("\tDestination name: " + rdn.getValue());
+                  destination = rdn.getValue().toString();
+               }
+               if (rdn.getType().equals("ou")) {
+                  String rawDestinationType = rdn.getValue().toString();
+                  if (rawDestinationType.toLowerCase().contains("queue")) {
+                     destinationType = "queue";
+                  }
+                  else if (rawDestinationType.toLowerCase().contains("topic")) {
+                     destinationType = "topic";
+                  }
+                  ActiveMQServerLogger.LOGGER.debug("\tDestination type: " + destinationType);
+               }
+            }
+            ActiveMQServerLogger.LOGGER.debug("\tAttributes: " + attrs);
+            Attribute attr = attrs.get(roleAttribute);
+            NamingEnumeration<?> e = attr.getAll();
+            Set<Role> roles = securityRoles.get(destination);
+            boolean exists = false;
+            if (roles == null) {
+               roles = new HashSet<>();
+            }
+            else {
+               exists = true;
+            }
+
+            while (e.hasMore()) {
+               String value = (String) e.next();
+               LdapName ldapname = new LdapName(value);
+               Rdn rdn = ldapname.getRdn(ldapname.size() - 1);
+               String roleName = rdn.getValue().toString();
+               ActiveMQServerLogger.LOGGER.debug("\tRole name: " + roleName);
+               Role role = new Role(roleName,
+                                    permissionType.equalsIgnoreCase(writePermissionValue),
+                                    permissionType.equalsIgnoreCase(readPermissionValue),
+                                    permissionType.equalsIgnoreCase(adminPermissionValue),
+                                    permissionType.equalsIgnoreCase(adminPermissionValue),
+                                    permissionType.equalsIgnoreCase(adminPermissionValue),
+                                    permissionType.equalsIgnoreCase(adminPermissionValue),
+                                    false); // there is no permission from ActiveMQ 5.x that corresponds to the "manage" permission in ActiveMQ Artemis
+               roles.add(role);
+            }
+
+            if (!exists) {
+               securityRoles.put(destination, roles);
+            }
+         }
+      }
+      catch (Exception e) {
+         ActiveMQServerLogger.LOGGER.errorPopulatingSecurityRolesFromLDAP(e);
+      }
+
+      this.securityRoles = securityRoles;
+      return this;
+   }
+}

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/fe4dafed/artemis-server/src/main/resources/schema/artemis-configuration.xsd
----------------------------------------------------------------------
diff --git a/artemis-server/src/main/resources/schema/artemis-configuration.xsd b/artemis-server/src/main/resources/schema/artemis-configuration.xsd
index 5ab8b76..a76395c 100644
--- a/artemis-server/src/main/resources/schema/artemis-configuration.xsd
+++ b/artemis-server/src/main/resources/schema/artemis-configuration.xsd
@@ -711,6 +711,42 @@
                         </xsd:attribute>
                      </xsd:complexType>
                   </xsd:element>
+                  <xsd:element name="security-setting-plugin" maxOccurs="unbounded" minOccurs="0">
+                     <xsd:complexType>
+                        <xsd:annotation>
+                           <xsd:documentation>
+                              a plugin
+                           </xsd:documentation>
+                        </xsd:annotation>
+                        <xsd:sequence>
+                           <xsd:element name="setting" maxOccurs="unbounded" minOccurs="0">
+                              <xsd:complexType>
+                                 <xsd:attribute name="name" type="xsd:string" use="required">
+                                    <xsd:annotation>
+                                       <xsd:documentation>
+                                          the name of the setting
+                                       </xsd:documentation>
+                                    </xsd:annotation>
+                                 </xsd:attribute>
+                                 <xsd:attribute name="value" type="xsd:string" use="required">
+                                    <xsd:annotation>
+                                       <xsd:documentation>
+                                          the value for the setting
+                                       </xsd:documentation>
+                                    </xsd:annotation>
+                                 </xsd:attribute>
+                              </xsd:complexType>
+                           </xsd:element>
+                        </xsd:sequence>
+                        <xsd:attribute name="class-name" type="xsd:string" use="required">
+                           <xsd:annotation>
+                              <xsd:documentation>
+                                 the name of the plugin class to instantiate
+                              </xsd:documentation>
+                           </xsd:annotation>
+                        </xsd:attribute>
+                     </xsd:complexType>
+                  </xsd:element>
                </xsd:sequence>
             </xsd:complexType>
          </xsd:element>

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/fe4dafed/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/FileConfigurationTest.java
----------------------------------------------------------------------
diff --git a/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/FileConfigurationTest.java b/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/FileConfigurationTest.java
index b809aa4..587d281 100644
--- a/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/FileConfigurationTest.java
+++ b/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/FileConfigurationTest.java
@@ -23,6 +23,7 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.StandardCopyOption;
 import java.util.Collections;
+import java.util.List;
 
 import org.apache.activemq.artemis.api.core.BroadcastGroupConfiguration;
 import org.apache.activemq.artemis.api.core.DiscoveryGroupConfiguration;
@@ -39,7 +40,9 @@ import org.apache.activemq.artemis.core.config.ha.LiveOnlyPolicyConfiguration;
 import org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants;
 import org.apache.activemq.artemis.core.security.Role;
 import org.apache.activemq.artemis.core.server.JournalType;
+import org.apache.activemq.artemis.core.server.SecuritySettingPlugin;
 import org.apache.activemq.artemis.core.server.cluster.impl.MessageLoadBalancingType;
+import org.apache.activemq.artemis.core.server.impl.LegacyLDAPSecuritySettingPlugin;
 import org.apache.activemq.artemis.core.settings.impl.SlowConsumerPolicy;
 import org.junit.Assert;
 import org.junit.Test;
@@ -339,6 +342,22 @@ public class FileConfigurationTest extends ConfigurationImplTest {
       assertTrue(a2Role.isDeleteNonDurableQueue());
       assertFalse(a2Role.isManage());
 
+      List<SecuritySettingPlugin> securitySettingPlugins = conf.getSecuritySettingPlugins();
+      SecuritySettingPlugin securitySettingPlugin = securitySettingPlugins.get(0);
+      assertTrue(securitySettingPlugin instanceof LegacyLDAPSecuritySettingPlugin);
+      LegacyLDAPSecuritySettingPlugin legacyLDAPSecuritySettingPlugin = (LegacyLDAPSecuritySettingPlugin) securitySettingPlugin;
+      assertEquals(legacyLDAPSecuritySettingPlugin.getInitialContextFactory(), "testInitialContextFactory");
+      assertEquals(legacyLDAPSecuritySettingPlugin.getConnectionURL(), "testConnectionURL");
+      assertEquals(legacyLDAPSecuritySettingPlugin.getConnectionUsername(), "testConnectionUsername");
+      assertEquals(legacyLDAPSecuritySettingPlugin.getConnectionPassword(), "testConnectionPassword");
+      assertEquals(legacyLDAPSecuritySettingPlugin.getConnectionProtocol(), "testConnectionProtocol");
+      assertEquals(legacyLDAPSecuritySettingPlugin.getAuthentication(), "testAuthentication");
+      assertEquals(legacyLDAPSecuritySettingPlugin.getDestinationBase(), "testDestinationBase");
+      assertEquals(legacyLDAPSecuritySettingPlugin.getFilter(), "testFilter");
+      assertEquals(legacyLDAPSecuritySettingPlugin.getRoleAttribute(), "testRoleAttribute");
+      assertEquals(legacyLDAPSecuritySettingPlugin.getAdminPermissionValue(), "testAdminPermissionValue");
+      assertEquals(legacyLDAPSecuritySettingPlugin.getReadPermissionValue(), "testReadPermissionValue");
+      assertEquals(legacyLDAPSecuritySettingPlugin.getWritePermissionValue(), "testWritePermissionValue");
    }
 
    @Test

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/fe4dafed/artemis-server/src/test/resources/ConfigurationTest-full-config.xml
----------------------------------------------------------------------
diff --git a/artemis-server/src/test/resources/ConfigurationTest-full-config.xml b/artemis-server/src/test/resources/ConfigurationTest-full-config.xml
index 0514788..5c4a0a2 100644
--- a/artemis-server/src/test/resources/ConfigurationTest-full-config.xml
+++ b/artemis-server/src/test/resources/ConfigurationTest-full-config.xml
@@ -232,6 +232,20 @@
          <security-setting match="a2">
             <permission type="deleteNonDurableQueue" roles="a2.1"/>
          </security-setting>
+         <security-setting-plugin class-name="org.apache.activemq.artemis.core.server.impl.LegacyLDAPSecuritySettingPlugin">
+            <setting name="initialContextFactory" value="testInitialContextFactory"/>
+            <setting name="connectionURL" value="testConnectionURL"/>
+            <setting name="connectionUsername" value="testConnectionUsername"/>
+            <setting name="connectionPassword" value="testConnectionPassword"/>
+            <setting name="connectionProtocol" value="testConnectionProtocol"/>
+            <setting name="authentication" value="testAuthentication"/>
+            <setting name="destinationBase" value="testDestinationBase"/>
+            <setting name="filter" value="testFilter"/>
+            <setting name="roleAttribute" value="testRoleAttribute"/>
+            <setting name="adminPermissionValue" value="testAdminPermissionValue"/>
+            <setting name="readPermissionValue" value="testReadPermissionValue"/>
+            <setting name="writePermissionValue" value="testWritePermissionValue"/>
+         </security-setting-plugin>
       </security-settings>
 
       <address-settings>

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/fe4dafed/docs/user-manual/en/security.md
----------------------------------------------------------------------
diff --git a/docs/user-manual/en/security.md b/docs/user-manual/en/security.md
index 34e1a49..b631b40 100644
--- a/docs/user-manual/en/security.md
+++ b/docs/user-manual/en/security.md
@@ -120,6 +120,121 @@ permissions in more specific security-setting blocks by simply not
 specifying them. Otherwise it would not be possible to deny permissions
 in sub-groups of addresses.
 
+## Security Setting Plugin
+
+Aside from configuring sets of permissions via XML these permissions can also be
+configured via plugins which implement `org.apache.activemq.artemis.core.server.SecuritySettingPlugin`.
+One or more plugins can be defined and configured alongside the normal XML, e.g.:
+
+    <security-settings>
+       ...
+       <security-setting-plugin class-name="org.apache.activemq.artemis.core.server.impl.LegacyLDAPSecuritySettingPlugin">
+          <setting name="initialContextFactory" value="com.sun.jndi.ldap.LdapCtxFactory"/>
+          <setting name="connectionURL" value="ldap://localhost:1024"/>
+          <setting name="connectionUsername" value="uid=admin,ou=system"/>
+          <setting name="connectionPassword" value="secret"/>
+          <setting name="connectionProtocol" value="s"/>
+          <setting name="authentication" value="simple"/>
+       </security-setting-plugin>
+    </security-settings>
+
+Most of this configuration is specific to the plugin implementation. However, there are two configuration details that
+will be specified for every implementation:
+
+-   `class-name`. This attribute of `security-setting-plugin` indicates the name of the class which implements
+    `org.apache.activemq.artemis.core.server.SecuritySettingPlugin`.
+
+-   `setting`. Each of these elements represents a name/value pair that will be passed to the implementation for configuration
+    purposes.
+
+See the JavaDoc on `org.apache.activemq.artemis.core.server.SecuritySettingPlugin` for further details about the interface
+and what each method is expected to do.
+
+### Available plugins
+
+#### LegacyLDAPSecuritySettingPlugin
+
+This plugin will read the security information that was previously handled by [`LDAPAuthorizationMap`](http://activemq.apache.org/security.html)
+and the [`cachedLDAPAuthorizationMap`](http://activemq.apache.org/cached-ldap-authorization-module.html) in Apache ActiveMQ 5.x
+and turn it into Artemis security settings where possible. The security implementations of ActiveMQ 5.x and Artemis don't
+match perfectly so some translation must occur to achieve near equivalent functionality.
+
+Here is an example of the plugin's configuration:
+
+    <security-setting-plugin class-name="org.apache.activemq.artemis.core.server.impl.LegacyLDAPSecuritySettingPlugin">
+       <setting name="initialContextFactory" value="com.sun.jndi.ldap.LdapCtxFactory"/>
+       <setting name="connectionURL" value="ldap://localhost:1024"/>
+       <setting name="connectionUsername" value="uid=admin,ou=system"/>
+       <setting name="connectionPassword" value="secret"/>
+       <setting name="connectionProtocol" value="s"/>
+       <setting name="authentication" value="simple"/>
+    </security-setting-plugin>
+
+-   `class-name`. The implementation is `org.apache.activemq.artemis.core.server.impl.LegacyLDAPSecuritySettingPlugin`.
+
+-   `initialContextFactory`. The initial context factory used to connect to LDAP. It must always be set to
+    `com.sun.jndi.ldap.LdapCtxFactory` (i.e. the default value).
+
+-   `connectionURL`. Specifies the location of the directory server using an ldap URL, `ldap://Host:Port`. You can
+    optionally qualify this URL, by adding a forward slash, `/`, followed by the DN of a particular node in the directory
+    tree. For example, `ldap://ldapserver:10389/ou=system`. The default is `ldap://localhost:1024`.
+
+-   `connectionUsername`. The DN of the user that opens the connection to the directory server. For example, `uid=admin,ou=system`.
+    Directory servers generally require clients to present username/password credentials in order to open a connection.
+
+-   `connectionPassword`. The password that matches the DN from `connectionUsername`. In the directory server, in the
+    DIT, the password is normally stored as a `userPassword` attribute in the corresponding directory entry.
+
+-   `connectionProtocol`. Currently the only supported value is a blank string. In future, this option will allow you to
+    select the Secure Socket Layer (SSL) for the connection to the directory server. Note: this option must be set
+    explicitly to an empty string, because it has no default value.
+
+-   `authentication`. Specifies the authentication method used when binding to the LDAP server. Can take either of the
+     values, `simple` (username and password, the default value) or `none` (anonymous). Note: Simple Authentication and
+     Security Layer (SASL) authentication is currently not supported.
+
+-   `destinationBase`. Specifies the DN of the node whose children provide the permissions for all destinations. In this
+    case the DN is a literal value (that is, no string substitution is performed on the property value).  For example, a
+    typical value of this property is `ou=destinations,o=ActiveMQ,ou=system` (i.e. the default value).
+
+-   `filter`. Specifies an LDAP search filter, which is used when looking up the permissions for any kind of destination.
+    The search filter attempts to match one of the children or descendants of the queue or topic node. The default value
+    is `(cn=*)`.
+
+-   `roleAttribute`. Specifies an attribute of the node matched by `filter`, whose value is the DN of a role. Default
+    value is `uniqueMember`.
+
+-   `adminPermissionValue`. Specifies a value that matches the `admin` permission. The default value is `admin`.
+
+-   `readPermissionValue`. Specifies a value that matches the `read` permission. The default value is `read`.
+
+-   `writePermissionValue`. Specifies a value that matches the `write` permission. The default value is `write`.
+
+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. It's worth noting that
+since the name of queue or topic coming from LDAP will server as the "match" for the security-setting the security-setting
+may not be applied as expected to JMS destinations since Artemis always prefixes JMS destinations with "jms.queue." or
+"jms.topic." as necessary.
+
+ActiveMQ 5.x only has 3 permission types - `read`, `write`, and `admin`. These permission types are described on their
+[website](http://activemq.apache.org/security.html). However, as described previously, ActiveMQ Artemis has 6 permission
+types - `createDurableQueue`, `deleteDurableQueue`, `createNonDurableQueue`, `deleteNonDurableQueue`, `send`, `consume`,
+and `manage`. Here's how the old types are mapped to the new types:
+
+-   `read` - `consume`
+-   `write` - `send`
+-   `admin` - `createDurableQueue`, `deleteDurableQueue`, `createNonDurableQueue`, `deleteNonDurableQueue`
+
+As mentioned, there are a few places where a translation was performed to achieve some equivalence.:
+
+-   This mapping doesn't include the Artemis `manage` permission type since there is no type analogous for that in ActiveMQ
+    5.x.
+
+-   The `admin` permission in ActiveMQ 5.x relates to whether or not the broker will auto-create a destination if
+    it doesn't exist and the user sends a message to it. Artemis automatically allows the automatic creation of a
+    destination if the user has permission to send message to it. Therefore, the plugin will map the `admin` permission
+    to the 4 aforementioned permissions in Artemis.
+
 ## Secure Sockets Layer (SSL) Transport
 
 When messaging clients are connected to servers, or servers are

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/fe4dafed/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/LegacyLDAPSecuritySettingPluginTest.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..89de0e9
--- /dev/null
+++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/LegacyLDAPSecuritySettingPluginTest.java
@@ -0,0 +1,317 @@
+/*
+ * 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.NameClassPair;
+import javax.naming.NamingEnumeration;
+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.HashSet;
+import java.util.Hashtable;
+
+import org.apache.activemq.artemis.api.core.ActiveMQException;
+import org.apache.activemq.artemis.api.core.SimpleString;
+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.ClientConsumer;
+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.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.integ.AbstractLdapTestUnit;
+import org.apache.directory.server.core.integ.FrameworkRunner;
+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)
+@CreateLdapServer(transports = {@CreateTransport(protocol = "LDAP", port = 1024)})
+@ApplyLdifFiles("AMQauth.ldif")
+public class LegacyLDAPSecuritySettingPluginTest extends AbstractLdapTestUnit {
+
+   static {
+      String path = System.getProperty("java.security.auth.login.config");
+      if (path == null) {
+         URL resource = LegacyLDAPSecuritySettingPluginTest.class.getClassLoader().getResource("login.config");
+         if (resource != null) {
+            path = resource.getFile();
+            System.setProperty("java.security.auth.login.config", path);
+         }
+      }
+   }
+
+   private ServerLocator locator;
+
+   public static final String TARGET_TMP = "./target/tmp";
+   private static final String PRINCIPAL = "uid=admin,ou=system";
+   private static final String CREDENTIALS = "secret";
+
+
+   public LegacyLDAPSecuritySettingPluginTest() {
+      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.createServerLocatorWithHA(new TransportConfiguration(InVMConnectorFactory.class.getCanonicalName()));
+      testDir = temporaryFolder.getRoot().getAbsolutePath();
+   }
+
+   @SuppressWarnings("unchecked")
+   @Test
+   public void testRunning() throws Exception {
+      Hashtable 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);
+      DirContext ctx = new InitialDirContext(env);
+
+      HashSet set = new HashSet();
+
+      NamingEnumeration list = ctx.list("ou=system");
+
+      while (list.hasMore()) {
+         NameClassPair ncp = (NameClassPair) list.next();
+         set.add(ncp.getName());
+      }
+
+      Assert.assertTrue(set.contains("uid=admin"));
+      Assert.assertTrue(set.contains("ou=users"));
+      Assert.assertTrue(set.contains("ou=groups"));
+      Assert.assertTrue(set.contains("ou=configuration"));
+      Assert.assertTrue(set.contains("prefNodeName=sysPrefRoot"));
+   }
+
+   @Test
+   public void testBasicPluginAuthorization() throws Exception {
+      ActiveMQServer server = getActiveMQServer();
+      server.start();
+      ClientSessionFactory cf = locator.createSessionFactory();
+      String name = "queue1";
+
+      try {
+         ClientSession session = cf.createSession("first", "secret", false, true, true, false, 0);
+         session.createQueue(SimpleString.toSimpleString(name), SimpleString.toSimpleString(name));
+         ClientProducer producer = session.createProducer();
+         producer.send(name, session.createMessage(false));
+         session.close();
+      }
+      catch (ActiveMQException e) {
+         e.printStackTrace();
+         Assert.fail("should not throw exception");
+      }
+
+      cf.close();
+      locator.close();
+      server.stop();
+   }
+
+   @Test
+   public void testPluginAuthorizationNegative() throws Exception {
+      final SimpleString ADDRESS = new SimpleString("queue2");
+      final SimpleString QUEUE = new SimpleString("queue2");
+
+      ActiveMQServer server = getActiveMQServer();
+      server.start();
+      server.createQueue(ADDRESS, QUEUE, null, true, false);
+
+      ClientSessionFactory cf = locator.createSessionFactory();
+      ClientSession session = cf.createSession("second", "secret", false, true, true, false, 0);
+
+      // CREATE_DURABLE_QUEUE
+      try {
+         session.createQueue(ADDRESS, QUEUE, true);
+         Assert.fail("should throw exception here");
+      }
+      catch (ActiveMQException e) {
+         // ignore
+      }
+
+      // DELETE_DURABLE_QUEUE
+      try {
+         session.deleteQueue(QUEUE);
+         Assert.fail("should throw exception here");
+      }
+      catch (ActiveMQException e) {
+         // ignore
+      }
+
+      // CREATE_NON_DURABLE_QUEUE
+      try {
+         session.createQueue(ADDRESS, QUEUE, false);
+         Assert.fail("should throw exception here");
+      }
+      catch (ActiveMQException e) {
+         // ignore
+      }
+
+      // DELETE_NON_DURABLE_QUEUE
+      try {
+         session.deleteQueue(QUEUE);
+         Assert.fail("should throw exception here");
+      }
+      catch (ActiveMQException e) {
+         // ignore
+      }
+
+      // PRODUCE
+      try {
+         ClientProducer producer = session.createProducer(ADDRESS);
+         producer.send(session.createMessage(true));
+         Assert.fail("should throw exception here");
+      }
+      catch (ActiveMQException e) {
+         // ignore
+      }
+
+      // CONSUME
+      try {
+         ClientConsumer consumer = session.createConsumer(QUEUE);
+         Assert.fail("should throw exception here");
+      }
+      catch (ActiveMQException e) {
+         // ignore
+      }
+
+      session.close();
+      cf.close();
+      locator.close();
+      server.stop();
+   }
+
+   @Test
+   public void testPluginAuthorizationPositive() throws Exception {
+      final SimpleString ADDRESS = new SimpleString("queue1");
+      final SimpleString QUEUE = new SimpleString("queue1");
+
+      ActiveMQServer server = getActiveMQServer();
+      server.start();
+
+      ClientSessionFactory cf = locator.createSessionFactory();
+      ClientSession session = cf.createSession("first", "secret", false, true, true, false, 0);
+
+      // CREATE_DURABLE_QUEUE
+      try {
+         session.createQueue(ADDRESS, QUEUE, true);
+      }
+      catch (ActiveMQException e) {
+         e.printStackTrace();
+         Assert.fail("should not throw exception here");
+      }
+
+      // DELETE_DURABLE_QUEUE
+      try {
+         session.deleteQueue(QUEUE);
+      }
+      catch (ActiveMQException e) {
+         e.printStackTrace();
+         Assert.fail("should not throw exception here");
+      }
+
+      // CREATE_NON_DURABLE_QUEUE
+      try {
+         session.createQueue(ADDRESS, QUEUE, false);
+      }
+      catch (ActiveMQException e) {
+         Assert.fail("should not throw exception here");
+      }
+
+      // DELETE_NON_DURABLE_QUEUE
+      try {
+         session.deleteQueue(QUEUE);
+      }
+      catch (ActiveMQException e) {
+         Assert.fail("should not throw exception here");
+      }
+
+      session.createQueue(ADDRESS, QUEUE, true);
+
+      // PRODUCE
+      try {
+         ClientProducer producer = session.createProducer(ADDRESS);
+         producer.send(session.createMessage(true));
+      }
+      catch (ActiveMQException e) {
+         Assert.fail("should not throw exception here");
+      }
+
+      // CONSUME
+      try {
+         session.createConsumer(QUEUE);
+      }
+      catch (ActiveMQException e) {
+         Assert.fail("should not throw exception here");
+      }
+
+      session.close();
+      cf.close();
+      locator.close();
+      server.stop();
+   }
+
+   private ActiveMQServer getActiveMQServer() {
+      LegacyLDAPSecuritySettingPlugin legacyLDAPSecuritySettingPlugin = new LegacyLDAPSecuritySettingPlugin()
+         .setInitialContextFactory("com.sun.jndi.ldap.LdapCtxFactory")
+         .setConnectionURL("ldap://localhost:1024")
+         .setConnectionUsername("uid=admin,ou=system")
+         .setConnectionPassword("secret")
+         .setConnectionProtocol("s")
+         .setAuthentication("simple")
+         .populateSecurityRoles();
+
+      ActiveMQJAASSecurityManager securityManager = new ActiveMQJAASSecurityManager();
+      securityManager.setConfigurationName("LDAPLogin");
+      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))
+         .setPersistenceEnabled(false)
+         .addSecuritySettingPlugin(legacyLDAPSecuritySettingPlugin);
+
+      return ActiveMQServers.newActiveMQServer(configuration, ManagementFactory.getPlatformMBeanServer(), securityManager, false);
+   }
+}

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/fe4dafed/tests/integration-tests/src/test/resources/AMQauth.ldif
----------------------------------------------------------------------
diff --git a/tests/integration-tests/src/test/resources/AMQauth.ldif b/tests/integration-tests/src/test/resources/AMQauth.ldif
new file mode 100755
index 0000000..e79257d
--- /dev/null
+++ b/tests/integration-tests/src/test/resources/AMQauth.ldif
@@ -0,0 +1,94 @@
+## ---------------------------------------------------------------------------
+## 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: o=ActiveMQ,ou=system
+objectclass: organization
+objectclass: top
+o: ActiveMQ
+
+dn: ou=users,o=ActiveMQ,ou=system
+objectclass: organizationalUnit
+objectclass: top
+ou: users
+
+dn: uid=first,ou=system
+uid: first
+userPassword: secret
+objectClass: account
+objectClass: simpleSecurityObject
+objectClass: top
+
+dn: uid=second,ou=system
+uid: second
+userPassword: secret
+objectClass: account
+objectClass: simpleSecurityObject
+objectClass: top
+
+dn: cn=role1,ou=system
+cn: role1
+member: uid=first,ou=system
+objectClass: groupOfNames
+objectClass: top
+
+dn: cn=role2,ou=system
+cn: role2
+member: uid=second,ou=system
+objectClass: groupOfNames
+objectClass: top
+
+dn: ou=destinations,o=ActiveMQ,ou=system
+objectclass: organizationalUnit
+objectclass: top
+ou: destinations
+
+dn: ou=queues,ou=destinations,o=ActiveMQ,ou=system
+objectclass: organizationalUnit
+objectclass: top
+ou: queues
+
+dn: uid=queue1,ou=queues,ou=destinations,o=ActiveMQ,ou=system
+objectclass: applicationProcess
+objectclass: uidObject
+objectclass: top
+uid: queue1
+cn: queue1
+
+dn: uid=queue2,ou=queues,ou=destinations,o=ActiveMQ,ou=system
+objectclass: applicationProcess
+objectclass: uidObject
+objectclass: top
+uid: queue2
+cn: queue2
+
+dn: cn=read,uid=queue1,ou=queues,ou=destinations,o=ActiveMQ,ou=system
+objectclass: groupOfUniqueNames
+objectclass: top
+cn: read
+uniquemember: uid=role1
+
+dn: cn=write,uid=queue1,ou=queues,ou=destinations,o=ActiveMQ,ou=system
+objectclass: groupOfUniqueNames
+objectclass: top
+cn: write
+uniquemember: uid=role1
+
+dn: cn=admin,uid=queue1,ou=queues,ou=destinations,o=ActiveMQ,ou=system
+objectclass: groupOfUniqueNames
+objectclass: top
+cn: admin
+uniquemember: uid=role1
\ No newline at end of file


Mime
View raw message