You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by cl...@apache.org on 2016/01/19 15:46:01 UTC
[3/3] activemq-artemis git commit: ARTEMIS-349 LDAP plugin listener
ARTEMIS-349 LDAP plugin listener
This feature required a bit of refactoring to the plugin interface itself as
well as a restriction on the configuration so that either only one plugin could
be specified or an ulimited number of security-setting matches. This was done
to prevent messy situations where a plugin could update settings from the XML
or even another plugin if there were overlapping matches.
Project: http://git-wip-us.apache.org/repos/asf/activemq-artemis/repo
Commit: http://git-wip-us.apache.org/repos/asf/activemq-artemis/commit/d94c044e
Tree: http://git-wip-us.apache.org/repos/asf/activemq-artemis/tree/d94c044e
Diff: http://git-wip-us.apache.org/repos/asf/activemq-artemis/diff/d94c044e
Branch: refs/heads/master
Commit: d94c044e900407134ca426827ccd7b73594aca6f
Parents: 3433f53
Author: jbertram <jb...@apache.org>
Authored: Mon Jan 11 16:39:35 2016 -0600
Committer: Clebert Suconic <cl...@apache.org>
Committed: Tue Jan 19 09:45:52 2016 -0500
----------------------------------------------------------------------
.../artemis/core/config/Configuration.java | 2 +
.../core/config/impl/ConfigurationImpl.java | 6 +
.../deployers/impl/FileConfigurationParser.java | 4 +-
.../core/server/SecuritySettingPlugin.java | 24 +-
.../core/server/impl/ActiveMQServerImpl.java | 9 +
.../impl/LegacyLDAPSecuritySettingPlugin.java | 375 +++++++++++++++----
.../resources/schema/artemis-configuration.xsd | 6 +-
.../impl/FileConfigurationParserTest.java | 12 +-
.../core/config/impl/FileConfigurationTest.java | 25 +-
.../resources/ConfigurationTest-full-config.xml | 14 -
.../resources/InvalidConfigurationTest6.xml | 45 +++
.../test/resources/securitySettingPlugin.xml | 40 ++
docs/user-manual/en/security.md | 47 +--
.../integration/openwire/OpenWireTestBase.java | 23 +-
.../integration/security/LDAPSecurityTest.java | 4 +-
...cyLDAPSecuritySettingPluginListenerTest.java | 352 +++++++++++++++++
.../LegacyLDAPSecuritySettingPluginTest.java | 3 +-
.../integration/security/SecurityTest.java | 10 +-
18 files changed, 817 insertions(+), 184 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/d94c044e/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 96d5050..e493769 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
@@ -868,6 +868,8 @@ public interface Configuration {
*/
Map<String, Set<Role>> getSecurityRoles();
+ Configuration putSecurityRoles(String match, Set<Role> roles);
+
Configuration setConnectorServiceConfigurations(List<ConnectorServiceConfiguration> configs);
Configuration addConnectorServiceConfiguration(ConnectorServiceConfiguration config);
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/d94c044e/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 fc36809..0a6582f 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
@@ -1145,6 +1145,12 @@ public class ConfigurationImpl implements Configuration, Serializable {
}
@Override
+ public ConfigurationImpl putSecurityRoles(String match, Set<Role> roles) {
+ securitySettings.put(match, roles);
+ return this;
+ }
+
+ @Override
public ConfigurationImpl setSecurityRoles(final Map<String, Set<Role>> securitySettings) {
this.securitySettings = securitySettings;
return this;
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/d94c044e/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 8b11b3b..e34207e 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
@@ -541,12 +541,12 @@ public final class FileConfigurationParser extends XMLConfigurationUtil {
NodeList list = node.getElementsByTagName(SECURITY_ELEMENT_NAME);
for (int i = 0; i < list.getLength(); i++) {
Pair<String, Set<Role>> securityItem = parseSecurityRoles(list.item(i));
- config.getSecurityRoles().put(securityItem.getA(), securityItem.getB());
+ config.putSecurityRoles(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());
+ config.addSecuritySettingPlugin(securityItem.getA().init(securityItem.getB()));
}
}
}
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/d94c044e/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
index 0803e2f..7b22b61 100644
--- 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
@@ -21,6 +21,7 @@ import java.util.Map;
import java.util.Set;
import org.apache.activemq.artemis.core.security.Role;
+import org.apache.activemq.artemis.core.settings.HierarchicalRepository;
public interface SecuritySettingPlugin extends Serializable {
/**
@@ -35,8 +36,14 @@ public interface SecuritySettingPlugin extends Serializable {
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.).
+ * Clean up all the associated resources associated with this plugin (e.g. LDAP connections, file handles, etc.)
+ *
+ * @return {@code this} instance
+ */
+ SecuritySettingPlugin stop();
+
+ /**
+ * Fetch the security role information from the external environment (e.g. file, LDAP, etc.) and return it.
*
* @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
@@ -44,14 +51,11 @@ public interface SecuritySettingPlugin extends Serializable {
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.
+ * This method is called by the broker during the start-up process. It's for plugins that might need to modify the
+ * security settings during runtime (e.g. LDAP plugin that uses a listener to receive updates, etc.). Any changes
+ * made to this {@code HierarchicalRepository} will be reflected in the broker.
*
- * @return {@code this} instance
+ * @param securityRepository
*/
- SecuritySettingPlugin populateSecurityRoles();
+ void setSecurityRepository(HierarchicalRepository<Set<Role>> securityRepository);
}
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/d94c044e/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java
----------------------------------------------------------------------
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java
index 58993fc..abdf428 100644
--- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java
@@ -104,6 +104,7 @@ import org.apache.activemq.artemis.core.server.NodeManager;
import org.apache.activemq.artemis.core.server.Queue;
import org.apache.activemq.artemis.core.server.QueueCreator;
import org.apache.activemq.artemis.core.server.QueueFactory;
+import org.apache.activemq.artemis.core.server.SecuritySettingPlugin;
import org.apache.activemq.artemis.core.server.ServerSession;
import org.apache.activemq.artemis.core.server.ServerSessionFactory;
import org.apache.activemq.artemis.core.server.ServiceRegistry;
@@ -696,6 +697,10 @@ public class ActiveMQServerImpl implements ActiveMQServer {
stopComponent(memoryManager);
+ for (SecuritySettingPlugin securitySettingPlugin : configuration.getSecuritySettingPlugins()) {
+ securitySettingPlugin.stop();
+ }
+
if (threadPool != null && !threadPoolSupplied) {
threadPool.shutdown();
try {
@@ -1739,6 +1744,10 @@ public class ActiveMQServerImpl implements ActiveMQServer {
for (Map.Entry<String, Set<Role>> entry : configuration.getSecurityRoles().entrySet()) {
securityRepository.addMatch(entry.getKey(), entry.getValue(), true);
}
+
+ for (SecuritySettingPlugin securitySettingPlugin : configuration.getSecuritySettingPlugins()) {
+ securitySettingPlugin.setSecurityRepository(securityRepository);
+ }
}
private void deployQueuesFromConfiguration() throws Exception {
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/d94c044e/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
index 21de3d7..936ae9a 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
@@ -25,17 +25,25 @@ import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
+import javax.naming.event.EventDirContext;
+import javax.naming.event.NamespaceChangeListener;
+import javax.naming.event.NamingEvent;
+import javax.naming.event.NamingExceptionEvent;
+import javax.naming.event.ObjectChangeListener;
import javax.naming.ldap.LdapName;
import javax.naming.ldap.Rdn;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
+import java.util.List;
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;
+import org.apache.activemq.artemis.core.server.SecuritySettingPlugin;
+import org.apache.activemq.artemis.core.settings.HierarchicalRepository;
public class LegacyLDAPSecuritySettingPlugin implements SecuritySettingPlugin {
private static final long serialVersionUID = 4793109879399750045L;
@@ -52,6 +60,7 @@ public class LegacyLDAPSecuritySettingPlugin implements SecuritySettingPlugin {
public static final String ADMIN_PERMISSION_VALUE = "adminPermissionValue";
public static final String READ_PERMISSION_VALUE = "readPermissionValue";
public static final String WRITE_PERMISSION_VALUE = "writePermissionValue";
+ public static final String ENABLE_LISTENER = "enableListener";
private String initialContextFactory = "com.sun.jndi.ldap.LdapCtxFactory";
private String connectionURL = "ldap://localhost:1024";
@@ -65,30 +74,43 @@ public class LegacyLDAPSecuritySettingPlugin implements SecuritySettingPlugin {
private String adminPermissionValue = "admin";
private String readPermissionValue = "read";
private String writePermissionValue = "write";
+ private boolean enableListener = true;
private DirContext context;
- private Map<String, Set<Role>> securityRoles = new HashMap<>();
+ private EventDirContext eventContext;
+ private Map<String, Set<Role>> securityRoles;
+ private HierarchicalRepository<Set<Role>> securityRepository;
@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);
+ initialContextFactory = getOption(options, INITIAL_CONTEXT_FACTORY, initialContextFactory);
+ connectionURL = getOption(options, CONNECTION_URL, connectionURL);
+ connectionUsername = getOption(options, CONNECTION_USERNAME, connectionUsername);
+ connectionPassword = getOption(options, CONNECTION_PASSWORD, connectionPassword);
+ connectionProtocol = getOption(options, CONNECTION_PROTOCOL, connectionProtocol);
+ authentication = getOption(options, AUTHENTICATION, authentication);
+ destinationBase = getOption(options, DESTINATION_BASE, destinationBase);
+ filter = getOption(options, FILTER, filter);
+ roleAttribute = getOption(options, ROLE_ATTRIBUTE, roleAttribute);
+ adminPermissionValue = getOption(options, ADMIN_PERMISSION_VALUE, adminPermissionValue);
+ readPermissionValue = getOption(options, READ_PERMISSION_VALUE, readPermissionValue);
+ writePermissionValue = getOption(options, WRITE_PERMISSION_VALUE, writePermissionValue);
+ enableListener = getOption(options, ENABLE_LISTENER, Boolean.TRUE.toString()).equalsIgnoreCase(Boolean.TRUE.toString());
}
return this;
}
+ private String getOption(Map<String, String> options, String key, String defaultValue) {
+ String result = options.get(key);
+ if (result == null) {
+ result = defaultValue;
+ }
+
+ return result;
+ }
+
public String getRoleAttribute() {
return roleAttribute;
}
@@ -197,11 +219,46 @@ public class LegacyLDAPSecuritySettingPlugin implements SecuritySettingPlugin {
return this;
}
- protected void open() throws NamingException {
+ public boolean isEnableListener() {
+ return enableListener;
+ }
+
+ public LegacyLDAPSecuritySettingPlugin setEnableListener(boolean enableListener) {
+ this.enableListener = enableListener;
+ return this;
+ }
+
+ protected boolean isContextAlive() {
+ boolean alive = false;
if (context != null) {
+ try {
+ context.getAttributes("");
+ alive = true;
+ }
+ catch (Exception e) {
+ }
+ }
+ return alive;
+ }
+
+ protected void open() throws NamingException {
+ if (isContextAlive()) {
return;
}
+ context = createContext();
+ eventContext = ((EventDirContext) context.lookup(""));
+
+ SearchControls searchControls = new SearchControls();
+ searchControls.setReturningAttributes(new String[]{roleAttribute});
+ searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
+
+ if (enableListener) {
+ eventContext.addNamingListener(destinationBase, filter, searchControls, new LDAPNamespaceChangeListener());
+ }
+ }
+
+ private DirContext createContext() throws NamingException {
Hashtable<String, String> env = new Hashtable<>();
env.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory);
if (connectionUsername != null && !"".equals(connectionUsername)) {
@@ -219,16 +276,18 @@ public class LegacyLDAPSecuritySettingPlugin implements SecuritySettingPlugin {
env.put(Context.SECURITY_PROTOCOL, connectionProtocol);
env.put(Context.PROVIDER_URL, connectionURL);
env.put(Context.SECURITY_AUTHENTICATION, authentication);
- context = new InitialDirContext(env);
+ return new InitialDirContext(env);
}
@Override
public Map<String, Set<Role>> getSecurityRoles() {
+ if (securityRoles == null) {
+ populateSecurityRoles();
+ }
return securityRoles;
}
- @Override
- public LegacyLDAPSecuritySettingPlugin populateSecurityRoles() {
+ private LegacyLDAPSecuritySettingPlugin populateSecurityRoles() {
ActiveMQServerLogger.LOGGER.populatingSecurityRolesFromLDAP(connectionURL);
try {
open();
@@ -242,80 +301,240 @@ public class LegacyLDAPSecuritySettingPlugin implements SecuritySettingPlugin {
searchControls.setReturningAttributes(new String[]{roleAttribute});
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
- Map<String, Set<Role>> securityRoles = new HashMap<>();
+ securityRoles = new HashMap<>();
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;
+ processSearchResult(securityRoles, searchResults.next());
+ }
+ }
+ catch (Exception e) {
+ ActiveMQServerLogger.LOGGER.errorPopulatingSecurityRolesFromLDAP(e);
+ }
+
+ return this;
+ }
+
+ @Override
+ public void setSecurityRepository(HierarchicalRepository<Set<Role>> securityRepository) {
+ this.securityRepository = securityRepository;
+ }
+
+ private void processSearchResult(Map<String, Set<Role>> securityRoles, SearchResult searchResult) throws NamingException {
+ Attributes attrs = searchResult.getAttributes();
+ if (attrs == null || attrs.size() == 0) {
+ return;
+ }
+ LdapName searchResultLdapName = new LdapName(searchResult.getName());
+ ActiveMQServerLogger.LOGGER.debug("LDAP search result : " + 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";
}
- 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);
- }
+ else if (rawDestinationType.toLowerCase().contains("topic")) {
+ destinationType = "topic";
}
- 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<>();
+ 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);
+ }
+ }
+
+ public SecuritySettingPlugin stop() {
+ try {
+ eventContext.close();
+ }
+ catch (NamingException e) {
+ // ignore
+ }
+
+ try {
+ context.close();
+ }
+ catch (NamingException e) {
+ // ignore
+ }
+
+ return this;
+ }
+
+ /**
+ * Handler for new policy entries in the directory.
+ *
+ * @param namingEvent
+ * the new entry event that occurred
+ */
+ public void objectAdded(NamingEvent namingEvent) {
+ Map<String, Set<Role>> newRoles = new HashMap<>();
+
+ try {
+ processSearchResult(newRoles, (SearchResult) namingEvent.getNewBinding());
+ for (Map.Entry<String, Set<Role>> entry : newRoles.entrySet()) {
+ Set<Role> existingRoles = securityRepository.getMatch(entry.getKey());
+ for (Role role : entry.getValue()) {
+ existingRoles.add(role);
}
- else {
- exists = true;
+ }
+ }
+ catch (NamingException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Handler for removed policy entries in the directory.
+ *
+ * @param namingEvent
+ * the removed entry event that occurred
+ */
+ public void objectRemoved(NamingEvent namingEvent) {
+ try {
+ LdapName ldapName = new LdapName(namingEvent.getOldBinding().getName());
+ String match = null;
+ for (Rdn rdn : ldapName.getRdns()) {
+ if (rdn.getType().equals("uid")) {
+ match = rdn.getValue().toString();
}
+ }
- 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);
+ Set<Role> roles = securityRepository.getMatch(match);
+
+ List<Role> rolesToRemove = new ArrayList<>();
+
+ for (Rdn rdn : ldapName.getRdns()) {
+ if (rdn.getValue().equals(writePermissionValue)) {
+ ActiveMQServerLogger.LOGGER.debug("Removing write permission");
+ for (Role role : roles) {
+ if (role.isSend()) {
+ rolesToRemove.add(role);
+ }
+ }
+ }
+ else if (rdn.getValue().equals(readPermissionValue)) {
+ ActiveMQServerLogger.LOGGER.debug("Removing read permission");
+ for (Role role : roles) {
+ if (role.isConsume()) {
+ rolesToRemove.add(role);
+ }
+ }
+ }
+ else if (rdn.getValue().equals(adminPermissionValue)) {
+ ActiveMQServerLogger.LOGGER.debug("Removing admin permission");
+ for (Role role : roles) {
+ if (role.isCreateDurableQueue() || role.isCreateNonDurableQueue() || role.isDeleteDurableQueue() || role.isDeleteNonDurableQueue()) {
+ rolesToRemove.add(role);
+ }
+ }
}
- if (!exists) {
- securityRoles.put(destination, roles);
+ for (Role roleToRemove : rolesToRemove) {
+ roles.remove(roleToRemove);
}
}
}
- catch (Exception e) {
- ActiveMQServerLogger.LOGGER.errorPopulatingSecurityRolesFromLDAP(e);
+ catch (NamingException e) {
+ e.printStackTrace();
}
+ }
- this.securityRoles = securityRoles;
- return this;
+ /**
+ * @param namingEvent
+ * the renaming entry event that occurred
+ */
+ public void objectRenamed(NamingEvent namingEvent) {
+
+ }
+
+ /**
+ * Handler for changed policy entries in the directory.
+ *
+ * @param namingEvent
+ * the changed entry event that occurred
+ */
+ public void objectChanged(NamingEvent namingEvent) {
+ objectRemoved(namingEvent);
+ objectAdded(namingEvent);
+ }
+
+ /**
+ * Handler for exception events from the registry.
+ *
+ * @param namingExceptionEvent
+ * the exception event
+ */
+ public void namingExceptionThrown(NamingExceptionEvent namingExceptionEvent) {
+ context = null;
+ ActiveMQServerLogger.LOGGER.error("Caught unexpected exception.", namingExceptionEvent.getException());
+ }
+
+ protected class LDAPNamespaceChangeListener implements NamespaceChangeListener, ObjectChangeListener {
+ @Override
+ public void namingExceptionThrown(NamingExceptionEvent evt) {
+ LegacyLDAPSecuritySettingPlugin.this.namingExceptionThrown(evt);
+ }
+
+ @Override
+ public void objectAdded(NamingEvent evt) {
+ LegacyLDAPSecuritySettingPlugin.this.objectAdded(evt);
+ }
+
+ @Override
+ public void objectRemoved(NamingEvent evt) {
+ LegacyLDAPSecuritySettingPlugin.this.objectRemoved(evt);
+ }
+
+ @Override
+ public void objectRenamed(NamingEvent evt) {
+ LegacyLDAPSecuritySettingPlugin.this.objectRenamed(evt);
+ }
+
+ @Override
+ public void objectChanged(NamingEvent evt) {
+ LegacyLDAPSecuritySettingPlugin.this.objectChanged(evt);
+ }
}
}
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/d94c044e/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 9174019..8703e7b 100644
--- a/artemis-server/src/main/resources/schema/artemis-configuration.xsd
+++ b/artemis-server/src/main/resources/schema/artemis-configuration.xsd
@@ -698,7 +698,7 @@
</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
- <xsd:sequence>
+ <xsd:choice>
<xsd:element name="security-setting" maxOccurs="unbounded" minOccurs="0">
<xsd:complexType>
<xsd:annotation>
@@ -735,7 +735,7 @@
</xsd:attribute>
</xsd:complexType>
</xsd:element>
- <xsd:element name="security-setting-plugin" maxOccurs="unbounded" minOccurs="0">
+ <xsd:element name="security-setting-plugin" maxOccurs="1" minOccurs="0">
<xsd:complexType>
<xsd:annotation>
<xsd:documentation>
@@ -771,7 +771,7 @@
</xsd:attribute>
</xsd:complexType>
</xsd:element>
- </xsd:sequence>
+ </xsd:choice>
</xsd:complexType>
</xsd:element>
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/d94c044e/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/FileConfigurationParserTest.java
----------------------------------------------------------------------
diff --git a/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/FileConfigurationParserTest.java b/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/FileConfigurationParserTest.java
index 99a45ef..84441a2 100644
--- a/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/FileConfigurationParserTest.java
+++ b/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/FileConfigurationParserTest.java
@@ -16,6 +16,11 @@
*/
package org.apache.activemq.artemis.core.config.impl;
+import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration;
import org.apache.activemq.artemis.core.config.Configuration;
import org.apache.activemq.artemis.core.config.FileDeploymentManager;
@@ -24,11 +29,6 @@ import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
import org.apache.activemq.artemis.utils.DefaultSensitiveStringCodec;
import org.junit.Test;
-import java.io.ByteArrayInputStream;
-import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
-import java.util.Map;
-
public class FileConfigurationParserTest extends ActiveMQTestBase {
/**
@@ -43,7 +43,7 @@ public class FileConfigurationParserTest extends ActiveMQTestBase {
*/
@Test
public void testSchemaValidation() throws Exception {
- for (int i = 0; i < 6; i++) {
+ for (int i = 0; i < 7; i++) {
String filename = "InvalidConfigurationTest" + i + ".xml";
FileConfiguration fc = new FileConfiguration();
FileDeploymentManager deploymentManager = new FileDeploymentManager(filename);
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/d94c044e/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 587d281..c4831bc 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
@@ -24,6 +24,8 @@ import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
import org.apache.activemq.artemis.api.core.BroadcastGroupConfiguration;
import org.apache.activemq.artemis.api.core.DiscoveryGroupConfiguration;
@@ -316,13 +318,15 @@ public class FileConfigurationTest extends ConfigurationImplTest {
assertEquals("color='blue'", conf.getQueueConfigurations().get(1).getFilterString());
assertEquals(false, conf.getQueueConfigurations().get(1).isDurable());
- assertEquals(2, conf.getSecurityRoles().size());
+ Map<String, Set<Role>> roles = conf.getSecurityRoles();
- assertTrue(conf.getSecurityRoles().containsKey("a1"));
+ assertEquals(2, roles.size());
- assertTrue(conf.getSecurityRoles().containsKey("a2"));
+ assertTrue(roles.containsKey("a1"));
- Role a1Role = conf.getSecurityRoles().get("a1").toArray(new Role[1])[0];
+ assertTrue(roles.containsKey("a2"));
+
+ Role a1Role = roles.get("a1").toArray(new Role[1])[0];
assertFalse(a1Role.isSend());
assertFalse(a1Role.isConsume());
@@ -332,7 +336,7 @@ public class FileConfigurationTest extends ConfigurationImplTest {
assertFalse(a1Role.isDeleteNonDurableQueue());
assertFalse(a1Role.isManage());
- Role a2Role = conf.getSecurityRoles().get("a2").toArray(new Role[1])[0];
+ Role a2Role = roles.get("a2").toArray(new Role[1])[0];
assertFalse(a2Role.isSend());
assertFalse(a2Role.isConsume());
@@ -341,8 +345,16 @@ public class FileConfigurationTest extends ConfigurationImplTest {
assertFalse(a2Role.isCreateNonDurableQueue());
assertTrue(a2Role.isDeleteNonDurableQueue());
assertFalse(a2Role.isManage());
+ }
+
+ @Test
+ public void testSecuritySettingPlugin() throws Exception {
+ FileConfiguration fc = new FileConfiguration();
+ FileDeploymentManager deploymentManager = new FileDeploymentManager("securitySettingPlugin.xml");
+ deploymentManager.addDeployable(fc);
+ deploymentManager.readConfiguration();
- List<SecuritySettingPlugin> securitySettingPlugins = conf.getSecuritySettingPlugins();
+ List<SecuritySettingPlugin> securitySettingPlugins = fc.getSecuritySettingPlugins();
SecuritySettingPlugin securitySettingPlugin = securitySettingPlugins.get(0);
assertTrue(securitySettingPlugin instanceof LegacyLDAPSecuritySettingPlugin);
LegacyLDAPSecuritySettingPlugin legacyLDAPSecuritySettingPlugin = (LegacyLDAPSecuritySettingPlugin) securitySettingPlugin;
@@ -358,6 +370,7 @@ public class FileConfigurationTest extends ConfigurationImplTest {
assertEquals(legacyLDAPSecuritySettingPlugin.getAdminPermissionValue(), "testAdminPermissionValue");
assertEquals(legacyLDAPSecuritySettingPlugin.getReadPermissionValue(), "testReadPermissionValue");
assertEquals(legacyLDAPSecuritySettingPlugin.getWritePermissionValue(), "testWritePermissionValue");
+ assertEquals(legacyLDAPSecuritySettingPlugin.isEnableListener(), false);
}
@Test
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/d94c044e/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 5c4a0a2..0514788 100644
--- a/artemis-server/src/test/resources/ConfigurationTest-full-config.xml
+++ b/artemis-server/src/test/resources/ConfigurationTest-full-config.xml
@@ -232,20 +232,6 @@
<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/d94c044e/artemis-server/src/test/resources/InvalidConfigurationTest6.xml
----------------------------------------------------------------------
diff --git a/artemis-server/src/test/resources/InvalidConfigurationTest6.xml b/artemis-server/src/test/resources/InvalidConfigurationTest6.xml
new file mode 100644
index 0000000..db3799a
--- /dev/null
+++ b/artemis-server/src/test/resources/InvalidConfigurationTest6.xml
@@ -0,0 +1,45 @@
+<!--
+ 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.
+-->
+<configuration
+ xmlns="urn:activemq"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="urn:activemq ../../src/config/common/schema/artemis-server.xsd">
+ <core xmlns="urn:activemq:core">
+ <security-settings>
+ <security-setting match="a1">
+ <permission type="createNonDurableQueue" roles="a1.1"/>
+ </security-setting>
+ <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>
+ </core>
+</configuration>
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/d94c044e/artemis-server/src/test/resources/securitySettingPlugin.xml
----------------------------------------------------------------------
diff --git a/artemis-server/src/test/resources/securitySettingPlugin.xml b/artemis-server/src/test/resources/securitySettingPlugin.xml
new file mode 100644
index 0000000..25207d5
--- /dev/null
+++ b/artemis-server/src/test/resources/securitySettingPlugin.xml
@@ -0,0 +1,40 @@
+<!--
+ 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.
+-->
+<configuration
+ xmlns="urn:activemq"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="urn:activemq ../../../../activemq-server/src/main/resources/schema/artemis-server.xsd">
+ <core xmlns="urn:activemq:core">
+ <security-settings>
+ <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"/>
+ <setting name="enableListener" value="false"/>
+ </security-setting-plugin>
+ </security-settings>
+ </core>
+</configuration>
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/d94c044e/docs/user-manual/en/security.md
----------------------------------------------------------------------
diff --git a/docs/user-manual/en/security.md b/docs/user-manual/en/security.md
index 5bb3372..f6e654d 100644
--- a/docs/user-manual/en/security.md
+++ b/docs/user-manual/en/security.md
@@ -122,12 +122,10 @@ 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.:
+Aside from configuring sets of permissions via XML these permissions can alternatively be
+configured via a plugin which implements `org.apache.activemq.artemis.core.server.SecuritySettingPlugin` 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"/>
@@ -210,6 +208,9 @@ Here is an example of the plugin's configuration:
- `writePermissionValue`. Specifies a value that matches the `write` permission. The default value is `write`.
+- `enableListener`. Whether or not to enable a listener that will automatically receive updates made in the LDAP server
+ and update the broker's authorization configuration in real-time. The default value is `true`.
+
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
@@ -254,46 +255,12 @@ This is the default security manager.
- The flexible, pluggable `ActiveMQJAASSecurityManager` which supports any standard JAAS login module. Artemis ships
with several login modules which will be discussed further down.
-
-### Non-JAAS Security Manager
-
-If you wish to use the legacy, deprecated `ActiveMQSecurityManager`, then it needs to be added to the `bootstrap.xml`
-configuration. Lets take a look at what this might look like:
-
- <basic-security>
- <users>file:${activemq.home}/config/non-clustered/artemis-users.properties</users>
- <roles>file:${activemq.home}/config/non-clustered/artemis-roles.properties</roles>
- <default-user>guest</default-user>
- </basic-security>
-
-The first 2 elements `users` and `roles` define what properties files should be used to load in the users and passwords.
-
-The next thing to note is the element `defaultuser`. This defines what user will be assumed when the client does not
-specify a username/password when creating a session. In this case they will be the user `guest`. Multiple roles can be
-specified for a default user in the `artemis-roles.properties`.
-
-Lets now take a look at the `artemis-users.properties` file, this is basically just a set of key value pairs that define
-the users and their password, like so:
-
- bill=activemq
- andrew=activemq1
- frank=activemq2
- sam=activemq3
-
-The `artemis-roles.properties` defines what groups these users belong too where the key is the user and the value is a
-comma separated list of the groups the user belongs to, like so:
-
- bill=user
- andrew=europe-user,user
- frank=us-user,news-user,user
- sam=news-user,user
### JAAS Security Manager
When using JAAS much of the configuration depends on which login module is used. However, there are a few commonalities
-for every case. Just like in the non-JAAS use-case, the first place to look is in `bootstrap.xml`. Here is an example
-using the `PropertiesLogin` JAAS login module which reads user, password, and role information from properties files
-much like the non-JAAS security manager implementation:
+for every case. The first place to look is in `bootstrap.xml`. Here is an example using the `PropertiesLogin` JAAS login
+module which reads user, password, and role information from properties files:
<jaas-security domain="PropertiesLogin"/>
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/d94c044e/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/openwire/OpenWireTestBase.java
----------------------------------------------------------------------
diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/openwire/OpenWireTestBase.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/openwire/OpenWireTestBase.java
index 275fad6..6a95bfc 100644
--- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/openwire/OpenWireTestBase.java
+++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/openwire/OpenWireTestBase.java
@@ -20,10 +20,8 @@ import javax.jms.ConnectionFactory;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
-import java.util.Map;
import java.util.Set;
import org.apache.activemq.artemis.api.core.SimpleString;
@@ -98,20 +96,13 @@ public class OpenWireTestBase extends ActiveMQTestBase {
//guest cannot do anything
Role destRole = new Role("manager", false, false, false, false, true, true, false);
- Map<String, Set<Role>> settings = server.getConfiguration().getSecurityRoles();
- if (settings == null) {
- settings = new HashMap<>();
- server.getConfiguration().setSecurityRoles(settings);
- }
- Set<Role> anySet = settings.get("#");
- if (anySet == null) {
- anySet = new HashSet<>();
- settings.put("#", anySet);
- }
- anySet.add(senderRole);
- anySet.add(receiverRole);
- anySet.add(guestRole);
- anySet.add(destRole);
+ Set<Role> roles = new HashSet<>();
+ roles.add(senderRole);
+ roles.add(receiverRole);
+ roles.add(guestRole);
+ roles.add(destRole);
+
+ server.getConfiguration().putSecurityRoles("#", roles);
}
jmsServer = new JMSServerManagerImpl(server);
namingContext = new InVMNamingContext();
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/d94c044e/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/LDAPSecurityTest.java
----------------------------------------------------------------------
diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/LDAPSecurityTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/LDAPSecurityTest.java
index e37414e..41f6ab9 100644
--- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/LDAPSecurityTest.java
+++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/LDAPSecurityTest.java
@@ -172,7 +172,7 @@ public class LDAPSecurityTest extends AbstractLdapTestUnit {
ActiveMQServer server = getActiveMQServer();
Set<Role> roles = new HashSet<>();
roles.add(new Role("programmers", false, false, false, false, false, false, false));
- server.getConfiguration().getSecurityRoles().put("#", roles);
+ server.getConfiguration().putSecurityRoles("#", roles);
server.start();
server.createQueue(ADDRESS, DURABLE_QUEUE, null, true, false);
server.createQueue(ADDRESS, NON_DURABLE_QUEUE, null, false, false);
@@ -260,7 +260,7 @@ public class LDAPSecurityTest extends AbstractLdapTestUnit {
ActiveMQServer server = getActiveMQServer();
Set<Role> roles = new HashSet<>();
roles.add(new Role("admins", true, true, true, true, true, true, true));
- server.getConfiguration().getSecurityRoles().put("#", roles);
+ server.getConfiguration().putSecurityRoles("#", roles);
server.start();
ClientSessionFactory cf = locator.createSessionFactory();
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/d94c044e/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/LegacyLDAPSecuritySettingPluginListenerTest.java
----------------------------------------------------------------------
diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/LegacyLDAPSecuritySettingPluginListenerTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/LegacyLDAPSecuritySettingPluginListenerTest.java
new file mode 100644
index 0000000..8f237ab
--- /dev/null
+++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/LegacyLDAPSecuritySettingPluginListenerTest.java
@@ -0,0 +1,352 @@
+/*
+ * 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.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.HashSet;
+import java.util.Hashtable;
+import java.util.Map;
+
+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 LegacyLDAPSecuritySettingPluginListenerTest extends AbstractLdapTestUnit {
+
+ static {
+ String path = System.getProperty("java.security.auth.login.config");
+ if (path == null) {
+ URL resource = LegacyLDAPSecuritySettingPluginListenerTest.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 LegacyLDAPSecuritySettingPluginListenerTest() {
+ 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 {
+ DirContext ctx = getContext();
+
+ 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"));
+ }
+
+ private DirContext getContext() throws NamingException {
+ 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);
+ return new InitialDirContext(env);
+ }
+
+ @Test
+ public void testProducerPermissionUpdate() throws Exception {
+ ActiveMQServer server = getActiveMQServer();
+ server.getConfiguration().setSecurityInvalidationInterval(0);
+ server.start();
+ ClientSessionFactory cf = locator.createSessionFactory();
+ String name = "queue1";
+ ClientSession session = cf.createSession("first", "secret", false, true, true, false, 0);
+ ClientSession session2 = cf.createSession("second", "secret", false, true, true, false, 0);
+ session.createQueue(SimpleString.toSimpleString(name), SimpleString.toSimpleString(name));
+ ClientProducer producer = session.createProducer();
+ ClientProducer producer2 = session2.createProducer();
+ producer.send(name, session.createMessage(true));
+
+ try {
+ producer2.send(name, session.createMessage(true));
+ Assert.fail("Sending here should fail due to the original security data.");
+ }
+ catch (ActiveMQException e) {
+ // ok
+ }
+
+ DirContext ctx = getContext();
+ BasicAttributes basicAttributes = new BasicAttributes();
+ basicAttributes.put("uniquemember", "uid=role2");
+ ctx.modifyAttributes("cn=write,uid=queue1,ou=queues,ou=destinations,o=ActiveMQ,ou=system", DirContext.REPLACE_ATTRIBUTE, basicAttributes);
+
+ producer2.send(name, session.createMessage(true));
+
+ try {
+ producer.send(name, session.createMessage(true));
+ Assert.fail("Sending here should fail due to the modified security data.");
+ }
+ catch (ActiveMQException e) {
+ // ok
+ }
+
+ cf.close();
+ locator.close();
+ server.stop();
+ }
+
+ @Test
+ public void testConsumerPermissionUpdate() throws Exception {
+ ActiveMQServer server = getActiveMQServer();
+ server.getConfiguration().setSecurityInvalidationInterval(0);
+ server.start();
+ ClientSessionFactory cf = locator.createSessionFactory();
+ String queue = "queue1";
+ ClientSession session = cf.createSession("first", "secret", false, true, true, false, 0);
+ ClientSession session2 = cf.createSession("second", "secret", false, true, true, false, 0);
+ session.createQueue(SimpleString.toSimpleString(queue), SimpleString.toSimpleString(queue));
+ ClientConsumer consumer = session.createConsumer(queue);
+ consumer.receiveImmediate();
+ consumer.close();
+ ClientConsumer consumer2 = null;
+
+ try {
+ session2.createConsumer(queue);
+ Assert.fail("Consuming here should fail due to the original security data.");
+ }
+ catch (ActiveMQException e) {
+ // ok
+ }
+
+ DirContext ctx = getContext();
+ BasicAttributes basicAttributes = new BasicAttributes();
+ basicAttributes.put("uniquemember", "uid=role2");
+ ctx.modifyAttributes("cn=read,uid=queue1,ou=queues,ou=destinations,o=ActiveMQ,ou=system", DirContext.REPLACE_ATTRIBUTE, basicAttributes);
+
+ consumer2 = session2.createConsumer(queue);
+ consumer2.receiveImmediate();
+ consumer2.close();
+
+ try {
+ session.createConsumer(queue);
+ Assert.fail("Sending here should fail due to the modified security data.");
+ }
+ catch (ActiveMQException e) {
+ // ok
+ }
+
+ cf.close();
+ locator.close();
+ server.stop();
+ }
+
+ @Test
+ public void testNewConsumerPermission() throws Exception {
+ ActiveMQServer server = getActiveMQServer();
+ server.getConfiguration().setSecurityInvalidationInterval(0);
+ server.start();
+ String queue = "queue2";
+ server.createQueue(SimpleString.toSimpleString(queue), SimpleString.toSimpleString(queue), null, false, false);
+ ClientSessionFactory cf = locator.createSessionFactory();
+ ClientSession session = cf.createSession("first", "secret", false, true, true, false, 0);
+ ClientConsumer consumer;
+
+ try {
+ session.createConsumer(queue);
+ Assert.fail("Consuming here should fail due to the original security data.");
+ }
+ catch (ActiveMQException e) {
+ // ok
+ }
+
+ DirContext ctx = getContext();
+ BasicAttributes basicAttributes = new BasicAttributes();
+ basicAttributes.put("uniquemember", "uid=role1");
+ Attribute objclass = new BasicAttribute("objectclass");
+ objclass.add("top");
+ objclass.add("groupOfUniqueNames");
+ basicAttributes.put(objclass);
+ ctx.bind("cn=read,uid=" + queue + ",ou=queues,ou=destinations,o=ActiveMQ,ou=system", null, basicAttributes);
+
+ consumer = session.createConsumer(queue);
+ consumer.receiveImmediate();
+
+ ctx.unbind("cn=read,uid=" + queue + ",ou=queues,ou=destinations,o=ActiveMQ,ou=system");
+ ctx.close();
+
+ try {
+ session.createConsumer(queue);
+ Assert.fail("Consuming here should fail due to the modified security data.");
+ }
+ catch (ActiveMQException e) {
+ // ok
+ }
+
+ consumer.close();
+
+ cf.close();
+ locator.close();
+ server.stop();
+ }
+
+ @Test
+ public void testNewProducerPermission() throws Exception {
+ ActiveMQServer server = getActiveMQServer();
+ server.getConfiguration().setSecurityInvalidationInterval(0);
+ server.start();
+ String queue = "queue2";
+ server.createQueue(SimpleString.toSimpleString(queue), SimpleString.toSimpleString(queue), null, false, false);
+ ClientSessionFactory cf = locator.createSessionFactory();
+ ClientSession session = cf.createSession("first", "secret", false, true, true, false, 0);
+ ClientProducer producer = session.createProducer(SimpleString.toSimpleString(queue));
+
+ try {
+ producer.send(session.createMessage(true));
+ Assert.fail("Producing here should fail due to the original security data.");
+ }
+ catch (ActiveMQException e) {
+ // ok
+ }
+
+ DirContext ctx = getContext();
+ BasicAttributes basicAttributes = new BasicAttributes();
+ basicAttributes.put("uniquemember", "uid=role1");
+ Attribute objclass = new BasicAttribute("objectclass");
+ objclass.add("top");
+ objclass.add("groupOfUniqueNames");
+ basicAttributes.put(objclass);
+ ctx.bind("cn=write,uid=" + queue + ",ou=queues,ou=destinations,o=ActiveMQ,ou=system", null, basicAttributes);
+
+ producer.send(session.createMessage(true));
+
+ ctx.unbind("cn=write,uid=" + queue + ",ou=queues,ou=destinations,o=ActiveMQ,ou=system");
+ ctx.close();
+
+ try {
+ producer.send(session.createMessage(true));
+ Assert.fail("Producing here should fail due to the modified security data.");
+ }
+ catch (ActiveMQException e) {
+ // ok
+ }
+
+ producer.close();
+
+ cf.close();
+ locator.close();
+ server.stop();
+ }
+
+ private ActiveMQServer getActiveMQServer() {
+ 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");
+ legacyLDAPSecuritySettingPlugin.init(map);
+// .setInitialContextFactory("com.sun.jndi.ldap.LdapCtxFactory")
+// .setConnectionURL("ldap://localhost:1024")
+// .setConnectionUsername("uid=admin,ou=system")
+// .setConnectionPassword("secret")
+// .setConnectionProtocol("s")
+// .setAuthentication("simple")
+// .setEnableListener(true);
+
+ ActiveMQJAASSecurityManager securityManager = new ActiveMQJAASSecurityManager("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/d94c044e/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
index 48f98bb..672d4c9 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
@@ -297,8 +297,7 @@ public class LegacyLDAPSecuritySettingPluginTest extends AbstractLdapTestUnit {
.setConnectionUsername("uid=admin,ou=system")
.setConnectionPassword("secret")
.setConnectionProtocol("s")
- .setAuthentication("simple")
- .populateSecurityRoles();
+ .setAuthentication("simple");
ActiveMQJAASSecurityManager securityManager = new ActiveMQJAASSecurityManager("LDAPLogin");
Configuration configuration = new ConfigurationImpl()
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/d94c044e/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/SecurityTest.java
----------------------------------------------------------------------
diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/SecurityTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/SecurityTest.java
index e5404ef..71cd369 100644
--- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/SecurityTest.java
+++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/SecurityTest.java
@@ -229,7 +229,7 @@ public class SecurityTest extends ActiveMQTestBase {
ActiveMQServer server = addServer(ActiveMQServers.newActiveMQServer(createDefaultInVMConfig().setSecurityEnabled(true), ManagementFactory.getPlatformMBeanServer(), securityManager, false));
Set<Role> roles = new HashSet<>();
roles.add(new Role("programmers", false, false, false, false, false, false, false));
- server.getConfiguration().getSecurityRoles().put("#", roles);
+ server.getConfiguration().putSecurityRoles("#", roles);
server.start();
server.createQueue(ADDRESS, DURABLE_QUEUE, null, true, false);
server.createQueue(ADDRESS, NON_DURABLE_QUEUE, null, false, false);
@@ -324,7 +324,7 @@ public class SecurityTest extends ActiveMQTestBase {
Set<Role> roles = new HashSet<>();
roles.add(new Role("programmers", false, false, false, false, false, false, false));
- server.getConfiguration().getSecurityRoles().put("#", roles);
+ server.getConfiguration().putSecurityRoles("#", roles);
server.start();
@@ -418,7 +418,7 @@ public class SecurityTest extends ActiveMQTestBase {
ActiveMQServer server = addServer(ActiveMQServers.newActiveMQServer(createDefaultInVMConfig().setSecurityEnabled(true), ManagementFactory.getPlatformMBeanServer(), securityManager, false));
Set<Role> roles = new HashSet<>();
roles.add(new Role("programmers", true, true, true, true, true, true, true));
- server.getConfiguration().getSecurityRoles().put("#", roles);
+ server.getConfiguration().putSecurityRoles("#", roles);
server.start();
ClientSessionFactory cf = createSessionFactory(locator);
@@ -506,7 +506,7 @@ public class SecurityTest extends ActiveMQTestBase {
Set<Role> roles = new HashSet<>();
roles.add(new Role("programmers", true, true, true, true, true, true, true));
- server.getConfiguration().getSecurityRoles().put("#", roles);
+ server.getConfiguration().putSecurityRoles("#", roles);
server.start();
TransportConfiguration tc = new TransportConfiguration(NETTY_CONNECTOR_FACTORY);
@@ -590,7 +590,7 @@ public class SecurityTest extends ActiveMQTestBase {
ActiveMQServer server = addServer(ActiveMQServers.newActiveMQServer(createDefaultInVMConfig().setSecurityEnabled(true), ManagementFactory.getPlatformMBeanServer(), securityManager, false));
Set<Role> roles = new HashSet<>();
roles.add(new Role("bar", true, true, true, true, true, true, true));
- server.getConfiguration().getSecurityRoles().put("#", roles);
+ server.getConfiguration().putSecurityRoles("#", roles);
server.start();
ClientSessionFactory cf = createSessionFactory(locator);