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.
This commit is contained in:
parent
3433f5345c
commit
d94c044e90
|
@ -868,6 +868,8 @@ public interface Configuration {
|
||||||
*/
|
*/
|
||||||
Map<String, Set<Role>> getSecurityRoles();
|
Map<String, Set<Role>> getSecurityRoles();
|
||||||
|
|
||||||
|
Configuration putSecurityRoles(String match, Set<Role> roles);
|
||||||
|
|
||||||
Configuration setConnectorServiceConfigurations(List<ConnectorServiceConfiguration> configs);
|
Configuration setConnectorServiceConfigurations(List<ConnectorServiceConfiguration> configs);
|
||||||
|
|
||||||
Configuration addConnectorServiceConfiguration(ConnectorServiceConfiguration config);
|
Configuration addConnectorServiceConfiguration(ConnectorServiceConfiguration config);
|
||||||
|
|
|
@ -1144,6 +1144,12 @@ public class ConfigurationImpl implements Configuration, Serializable {
|
||||||
return securitySettings;
|
return securitySettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConfigurationImpl putSecurityRoles(String match, Set<Role> roles) {
|
||||||
|
securitySettings.put(match, roles);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConfigurationImpl setSecurityRoles(final Map<String, Set<Role>> securitySettings) {
|
public ConfigurationImpl setSecurityRoles(final Map<String, Set<Role>> securitySettings) {
|
||||||
this.securitySettings = securitySettings;
|
this.securitySettings = securitySettings;
|
||||||
|
|
|
@ -541,12 +541,12 @@ public final class FileConfigurationParser extends XMLConfigurationUtil {
|
||||||
NodeList list = node.getElementsByTagName(SECURITY_ELEMENT_NAME);
|
NodeList list = node.getElementsByTagName(SECURITY_ELEMENT_NAME);
|
||||||
for (int i = 0; i < list.getLength(); i++) {
|
for (int i = 0; i < list.getLength(); i++) {
|
||||||
Pair<String, Set<Role>> securityItem = parseSecurityRoles(list.item(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);
|
list = node.getElementsByTagName(SECURITY_PLUGIN_ELEMENT_NAME);
|
||||||
for (int i = 0; i < list.getLength(); i++) {
|
for (int i = 0; i < list.getLength(); i++) {
|
||||||
Pair<SecuritySettingPlugin, Map<String, String>> securityItem = parseSecuritySettingPlugins(list.item(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()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.activemq.artemis.core.security.Role;
|
import org.apache.activemq.artemis.core.security.Role;
|
||||||
|
import org.apache.activemq.artemis.core.settings.HierarchicalRepository;
|
||||||
|
|
||||||
public interface SecuritySettingPlugin extends Serializable {
|
public interface SecuritySettingPlugin extends Serializable {
|
||||||
/**
|
/**
|
||||||
|
@ -35,8 +36,14 @@ public interface SecuritySettingPlugin extends Serializable {
|
||||||
SecuritySettingPlugin init(Map<String, String> options);
|
SecuritySettingPlugin init(Map<String, String> options);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Once {@code #populateSecurityRoles} is invoked this method should return the security role information from the
|
* Clean up all the associated resources associated with this plugin (e.g. LDAP connections, file handles, etc.)
|
||||||
* external environment (e.g. file, LDAP, 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
|
* @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
|
* {@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();
|
Map<String, Set<Role>> getSecurityRoles();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch the security role information from the external environment (e.g. file, LDAP, etc.). This method should put
|
* This method is called by the broker during the start-up process. It's for plugins that might need to modify the
|
||||||
* the security role information in the variable that is returned by {@code #getSecurityRoles()}. This method is
|
* security settings during runtime (e.g. LDAP plugin that uses a listener to receive updates, etc.). Any changes
|
||||||
* 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)}
|
* made to this {@code HierarchicalRepository} will be reflected in the broker.
|
||||||
* 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
|
* @param securityRepository
|
||||||
*/
|
*/
|
||||||
SecuritySettingPlugin populateSecurityRoles();
|
void setSecurityRepository(HierarchicalRepository<Set<Role>> securityRepository);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.Queue;
|
||||||
import org.apache.activemq.artemis.core.server.QueueCreator;
|
import org.apache.activemq.artemis.core.server.QueueCreator;
|
||||||
import org.apache.activemq.artemis.core.server.QueueFactory;
|
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.ServerSession;
|
||||||
import org.apache.activemq.artemis.core.server.ServerSessionFactory;
|
import org.apache.activemq.artemis.core.server.ServerSessionFactory;
|
||||||
import org.apache.activemq.artemis.core.server.ServiceRegistry;
|
import org.apache.activemq.artemis.core.server.ServiceRegistry;
|
||||||
|
@ -696,6 +697,10 @@ public class ActiveMQServerImpl implements ActiveMQServer {
|
||||||
|
|
||||||
stopComponent(memoryManager);
|
stopComponent(memoryManager);
|
||||||
|
|
||||||
|
for (SecuritySettingPlugin securitySettingPlugin : configuration.getSecuritySettingPlugins()) {
|
||||||
|
securitySettingPlugin.stop();
|
||||||
|
}
|
||||||
|
|
||||||
if (threadPool != null && !threadPoolSupplied) {
|
if (threadPool != null && !threadPoolSupplied) {
|
||||||
threadPool.shutdown();
|
threadPool.shutdown();
|
||||||
try {
|
try {
|
||||||
|
@ -1739,6 +1744,10 @@ public class ActiveMQServerImpl implements ActiveMQServer {
|
||||||
for (Map.Entry<String, Set<Role>> entry : configuration.getSecurityRoles().entrySet()) {
|
for (Map.Entry<String, Set<Role>> entry : configuration.getSecurityRoles().entrySet()) {
|
||||||
securityRepository.addMatch(entry.getKey(), entry.getValue(), true);
|
securityRepository.addMatch(entry.getKey(), entry.getValue(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (SecuritySettingPlugin securitySettingPlugin : configuration.getSecuritySettingPlugins()) {
|
||||||
|
securitySettingPlugin.setSecurityRepository(securityRepository);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deployQueuesFromConfiguration() throws Exception {
|
private void deployQueuesFromConfiguration() throws Exception {
|
||||||
|
|
|
@ -25,17 +25,25 @@ import javax.naming.directory.DirContext;
|
||||||
import javax.naming.directory.InitialDirContext;
|
import javax.naming.directory.InitialDirContext;
|
||||||
import javax.naming.directory.SearchControls;
|
import javax.naming.directory.SearchControls;
|
||||||
import javax.naming.directory.SearchResult;
|
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.LdapName;
|
||||||
import javax.naming.ldap.Rdn;
|
import javax.naming.ldap.Rdn;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.activemq.artemis.core.security.Role;
|
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.ActiveMQServerLogger;
|
||||||
|
import org.apache.activemq.artemis.core.server.SecuritySettingPlugin;
|
||||||
|
import org.apache.activemq.artemis.core.settings.HierarchicalRepository;
|
||||||
|
|
||||||
public class LegacyLDAPSecuritySettingPlugin implements SecuritySettingPlugin {
|
public class LegacyLDAPSecuritySettingPlugin implements SecuritySettingPlugin {
|
||||||
private static final long serialVersionUID = 4793109879399750045L;
|
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 ADMIN_PERMISSION_VALUE = "adminPermissionValue";
|
||||||
public static final String READ_PERMISSION_VALUE = "readPermissionValue";
|
public static final String READ_PERMISSION_VALUE = "readPermissionValue";
|
||||||
public static final String WRITE_PERMISSION_VALUE = "writePermissionValue";
|
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 initialContextFactory = "com.sun.jndi.ldap.LdapCtxFactory";
|
||||||
private String connectionURL = "ldap://localhost:1024";
|
private String connectionURL = "ldap://localhost:1024";
|
||||||
|
@ -65,30 +74,43 @@ public class LegacyLDAPSecuritySettingPlugin implements SecuritySettingPlugin {
|
||||||
private String adminPermissionValue = "admin";
|
private String adminPermissionValue = "admin";
|
||||||
private String readPermissionValue = "read";
|
private String readPermissionValue = "read";
|
||||||
private String writePermissionValue = "write";
|
private String writePermissionValue = "write";
|
||||||
|
private boolean enableListener = true;
|
||||||
|
|
||||||
private DirContext context;
|
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
|
@Override
|
||||||
public LegacyLDAPSecuritySettingPlugin init(Map<String, String> options) {
|
public LegacyLDAPSecuritySettingPlugin init(Map<String, String> options) {
|
||||||
if (options != null) {
|
if (options != null) {
|
||||||
initialContextFactory = options.get(INITIAL_CONTEXT_FACTORY);
|
initialContextFactory = getOption(options, INITIAL_CONTEXT_FACTORY, initialContextFactory);
|
||||||
connectionURL = options.get(CONNECTION_URL);
|
connectionURL = getOption(options, CONNECTION_URL, connectionURL);
|
||||||
connectionUsername = options.get(CONNECTION_USERNAME);
|
connectionUsername = getOption(options, CONNECTION_USERNAME, connectionUsername);
|
||||||
connectionPassword = options.get(CONNECTION_PASSWORD);
|
connectionPassword = getOption(options, CONNECTION_PASSWORD, connectionPassword);
|
||||||
connectionProtocol = options.get(CONNECTION_PROTOCOL);
|
connectionProtocol = getOption(options, CONNECTION_PROTOCOL, connectionProtocol);
|
||||||
authentication = options.get(AUTHENTICATION);
|
authentication = getOption(options, AUTHENTICATION, authentication);
|
||||||
destinationBase = options.get(DESTINATION_BASE);
|
destinationBase = getOption(options, DESTINATION_BASE, destinationBase);
|
||||||
filter = options.get(FILTER);
|
filter = getOption(options, FILTER, filter);
|
||||||
roleAttribute = options.get(ROLE_ATTRIBUTE);
|
roleAttribute = getOption(options, ROLE_ATTRIBUTE, roleAttribute);
|
||||||
adminPermissionValue = options.get(ADMIN_PERMISSION_VALUE);
|
adminPermissionValue = getOption(options, ADMIN_PERMISSION_VALUE, adminPermissionValue);
|
||||||
readPermissionValue = options.get(READ_PERMISSION_VALUE);
|
readPermissionValue = getOption(options, READ_PERMISSION_VALUE, readPermissionValue);
|
||||||
writePermissionValue = options.get(WRITE_PERMISSION_VALUE);
|
writePermissionValue = getOption(options, WRITE_PERMISSION_VALUE, writePermissionValue);
|
||||||
|
enableListener = getOption(options, ENABLE_LISTENER, Boolean.TRUE.toString()).equalsIgnoreCase(Boolean.TRUE.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
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() {
|
public String getRoleAttribute() {
|
||||||
return roleAttribute;
|
return roleAttribute;
|
||||||
}
|
}
|
||||||
|
@ -197,11 +219,46 @@ public class LegacyLDAPSecuritySettingPlugin implements SecuritySettingPlugin {
|
||||||
return this;
|
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) {
|
if (context != null) {
|
||||||
|
try {
|
||||||
|
context.getAttributes("");
|
||||||
|
alive = true;
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return alive;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void open() throws NamingException {
|
||||||
|
if (isContextAlive()) {
|
||||||
return;
|
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<>();
|
Hashtable<String, String> env = new Hashtable<>();
|
||||||
env.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory);
|
env.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory);
|
||||||
if (connectionUsername != null && !"".equals(connectionUsername)) {
|
if (connectionUsername != null && !"".equals(connectionUsername)) {
|
||||||
|
@ -219,16 +276,18 @@ public class LegacyLDAPSecuritySettingPlugin implements SecuritySettingPlugin {
|
||||||
env.put(Context.SECURITY_PROTOCOL, connectionProtocol);
|
env.put(Context.SECURITY_PROTOCOL, connectionProtocol);
|
||||||
env.put(Context.PROVIDER_URL, connectionURL);
|
env.put(Context.PROVIDER_URL, connectionURL);
|
||||||
env.put(Context.SECURITY_AUTHENTICATION, authentication);
|
env.put(Context.SECURITY_AUTHENTICATION, authentication);
|
||||||
context = new InitialDirContext(env);
|
return new InitialDirContext(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Set<Role>> getSecurityRoles() {
|
public Map<String, Set<Role>> getSecurityRoles() {
|
||||||
|
if (securityRoles == null) {
|
||||||
|
populateSecurityRoles();
|
||||||
|
}
|
||||||
return securityRoles;
|
return securityRoles;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private LegacyLDAPSecuritySettingPlugin populateSecurityRoles() {
|
||||||
public LegacyLDAPSecuritySettingPlugin populateSecurityRoles() {
|
|
||||||
ActiveMQServerLogger.LOGGER.populatingSecurityRolesFromLDAP(connectionURL);
|
ActiveMQServerLogger.LOGGER.populatingSecurityRolesFromLDAP(connectionURL);
|
||||||
try {
|
try {
|
||||||
open();
|
open();
|
||||||
|
@ -242,18 +301,32 @@ public class LegacyLDAPSecuritySettingPlugin implements SecuritySettingPlugin {
|
||||||
searchControls.setReturningAttributes(new String[]{roleAttribute});
|
searchControls.setReturningAttributes(new String[]{roleAttribute});
|
||||||
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
|
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
|
||||||
|
|
||||||
Map<String, Set<Role>> securityRoles = new HashMap<>();
|
securityRoles = new HashMap<>();
|
||||||
try {
|
try {
|
||||||
NamingEnumeration<SearchResult> searchResults = context.search(destinationBase, filter, searchControls);
|
NamingEnumeration<SearchResult> searchResults = context.search(destinationBase, filter, searchControls);
|
||||||
int i = 0;
|
|
||||||
while (searchResults.hasMore()) {
|
while (searchResults.hasMore()) {
|
||||||
SearchResult searchResult = searchResults.next();
|
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();
|
Attributes attrs = searchResult.getAttributes();
|
||||||
if (attrs == null || attrs.size() == 0) {
|
if (attrs == null || attrs.size() == 0) {
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
LdapName searchResultLdapName = new LdapName(searchResult.getName());
|
LdapName searchResultLdapName = new LdapName(searchResult.getName());
|
||||||
ActiveMQServerLogger.LOGGER.debug("LDAP search result " + ++i + ": " + searchResultLdapName);
|
ActiveMQServerLogger.LOGGER.debug("LDAP search result : " + searchResultLdapName);
|
||||||
String permissionType = null;
|
String permissionType = null;
|
||||||
String destination = null;
|
String destination = null;
|
||||||
String destinationType = "unknown";
|
String destinationType = "unknown";
|
||||||
|
@ -310,12 +383,158 @@ public class LegacyLDAPSecuritySettingPlugin implements SecuritySettingPlugin {
|
||||||
securityRoles.put(destination, roles);
|
securityRoles.put(destination, roles);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SecuritySettingPlugin stop() {
|
||||||
|
try {
|
||||||
|
eventContext.close();
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (NamingException e) {
|
||||||
ActiveMQServerLogger.LOGGER.errorPopulatingSecurityRolesFromLDAP(e);
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
context.close();
|
||||||
|
}
|
||||||
|
catch (NamingException e) {
|
||||||
|
// ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
this.securityRoles = securityRoles;
|
|
||||||
return this;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Role roleToRemove : rolesToRemove) {
|
||||||
|
roles.remove(roleToRemove);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (NamingException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -698,7 +698,7 @@
|
||||||
</xsd:documentation>
|
</xsd:documentation>
|
||||||
</xsd:annotation>
|
</xsd:annotation>
|
||||||
<xsd:complexType>
|
<xsd:complexType>
|
||||||
<xsd:sequence>
|
<xsd:choice>
|
||||||
<xsd:element name="security-setting" maxOccurs="unbounded" minOccurs="0">
|
<xsd:element name="security-setting" maxOccurs="unbounded" minOccurs="0">
|
||||||
<xsd:complexType>
|
<xsd:complexType>
|
||||||
<xsd:annotation>
|
<xsd:annotation>
|
||||||
|
@ -735,7 +735,7 @@
|
||||||
</xsd:attribute>
|
</xsd:attribute>
|
||||||
</xsd:complexType>
|
</xsd:complexType>
|
||||||
</xsd:element>
|
</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:complexType>
|
||||||
<xsd:annotation>
|
<xsd:annotation>
|
||||||
<xsd:documentation>
|
<xsd:documentation>
|
||||||
|
@ -771,7 +771,7 @@
|
||||||
</xsd:attribute>
|
</xsd:attribute>
|
||||||
</xsd:complexType>
|
</xsd:complexType>
|
||||||
</xsd:element>
|
</xsd:element>
|
||||||
</xsd:sequence>
|
</xsd:choice>
|
||||||
</xsd:complexType>
|
</xsd:complexType>
|
||||||
</xsd:element>
|
</xsd:element>
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,11 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.activemq.artemis.core.config.impl;
|
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.api.config.ActiveMQDefaultConfiguration;
|
||||||
import org.apache.activemq.artemis.core.config.Configuration;
|
import org.apache.activemq.artemis.core.config.Configuration;
|
||||||
import org.apache.activemq.artemis.core.config.FileDeploymentManager;
|
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.apache.activemq.artemis.utils.DefaultSensitiveStringCodec;
|
||||||
import org.junit.Test;
|
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 {
|
public class FileConfigurationParserTest extends ActiveMQTestBase {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -43,7 +43,7 @@ public class FileConfigurationParserTest extends ActiveMQTestBase {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testSchemaValidation() throws Exception {
|
public void testSchemaValidation() throws Exception {
|
||||||
for (int i = 0; i < 6; i++) {
|
for (int i = 0; i < 7; i++) {
|
||||||
String filename = "InvalidConfigurationTest" + i + ".xml";
|
String filename = "InvalidConfigurationTest" + i + ".xml";
|
||||||
FileConfiguration fc = new FileConfiguration();
|
FileConfiguration fc = new FileConfiguration();
|
||||||
FileDeploymentManager deploymentManager = new FileDeploymentManager(filename);
|
FileDeploymentManager deploymentManager = new FileDeploymentManager(filename);
|
||||||
|
|
|
@ -24,6 +24,8 @@ import java.nio.file.Path;
|
||||||
import java.nio.file.StandardCopyOption;
|
import java.nio.file.StandardCopyOption;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
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.BroadcastGroupConfiguration;
|
||||||
import org.apache.activemq.artemis.api.core.DiscoveryGroupConfiguration;
|
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("color='blue'", conf.getQueueConfigurations().get(1).getFilterString());
|
||||||
assertEquals(false, conf.getQueueConfigurations().get(1).isDurable());
|
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.isSend());
|
||||||
assertFalse(a1Role.isConsume());
|
assertFalse(a1Role.isConsume());
|
||||||
|
@ -332,7 +336,7 @@ public class FileConfigurationTest extends ConfigurationImplTest {
|
||||||
assertFalse(a1Role.isDeleteNonDurableQueue());
|
assertFalse(a1Role.isDeleteNonDurableQueue());
|
||||||
assertFalse(a1Role.isManage());
|
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.isSend());
|
||||||
assertFalse(a2Role.isConsume());
|
assertFalse(a2Role.isConsume());
|
||||||
|
@ -341,8 +345,16 @@ public class FileConfigurationTest extends ConfigurationImplTest {
|
||||||
assertFalse(a2Role.isCreateNonDurableQueue());
|
assertFalse(a2Role.isCreateNonDurableQueue());
|
||||||
assertTrue(a2Role.isDeleteNonDurableQueue());
|
assertTrue(a2Role.isDeleteNonDurableQueue());
|
||||||
assertFalse(a2Role.isManage());
|
assertFalse(a2Role.isManage());
|
||||||
|
}
|
||||||
|
|
||||||
List<SecuritySettingPlugin> securitySettingPlugins = conf.getSecuritySettingPlugins();
|
@Test
|
||||||
|
public void testSecuritySettingPlugin() throws Exception {
|
||||||
|
FileConfiguration fc = new FileConfiguration();
|
||||||
|
FileDeploymentManager deploymentManager = new FileDeploymentManager("securitySettingPlugin.xml");
|
||||||
|
deploymentManager.addDeployable(fc);
|
||||||
|
deploymentManager.readConfiguration();
|
||||||
|
|
||||||
|
List<SecuritySettingPlugin> securitySettingPlugins = fc.getSecuritySettingPlugins();
|
||||||
SecuritySettingPlugin securitySettingPlugin = securitySettingPlugins.get(0);
|
SecuritySettingPlugin securitySettingPlugin = securitySettingPlugins.get(0);
|
||||||
assertTrue(securitySettingPlugin instanceof LegacyLDAPSecuritySettingPlugin);
|
assertTrue(securitySettingPlugin instanceof LegacyLDAPSecuritySettingPlugin);
|
||||||
LegacyLDAPSecuritySettingPlugin legacyLDAPSecuritySettingPlugin = (LegacyLDAPSecuritySettingPlugin) securitySettingPlugin;
|
LegacyLDAPSecuritySettingPlugin legacyLDAPSecuritySettingPlugin = (LegacyLDAPSecuritySettingPlugin) securitySettingPlugin;
|
||||||
|
@ -358,6 +370,7 @@ public class FileConfigurationTest extends ConfigurationImplTest {
|
||||||
assertEquals(legacyLDAPSecuritySettingPlugin.getAdminPermissionValue(), "testAdminPermissionValue");
|
assertEquals(legacyLDAPSecuritySettingPlugin.getAdminPermissionValue(), "testAdminPermissionValue");
|
||||||
assertEquals(legacyLDAPSecuritySettingPlugin.getReadPermissionValue(), "testReadPermissionValue");
|
assertEquals(legacyLDAPSecuritySettingPlugin.getReadPermissionValue(), "testReadPermissionValue");
|
||||||
assertEquals(legacyLDAPSecuritySettingPlugin.getWritePermissionValue(), "testWritePermissionValue");
|
assertEquals(legacyLDAPSecuritySettingPlugin.getWritePermissionValue(), "testWritePermissionValue");
|
||||||
|
assertEquals(legacyLDAPSecuritySettingPlugin.isEnableListener(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -232,20 +232,6 @@
|
||||||
<security-setting match="a2">
|
<security-setting match="a2">
|
||||||
<permission type="deleteNonDurableQueue" roles="a2.1"/>
|
<permission type="deleteNonDurableQueue" roles="a2.1"/>
|
||||||
</security-setting>
|
</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>
|
</security-settings>
|
||||||
|
|
||||||
<address-settings>
|
<address-settings>
|
||||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -122,12 +122,10 @@ in sub-groups of addresses.
|
||||||
|
|
||||||
## Security Setting Plugin
|
## Security Setting Plugin
|
||||||
|
|
||||||
Aside from configuring sets of permissions via XML these permissions can also be
|
Aside from configuring sets of permissions via XML these permissions can alternatively be
|
||||||
configured via plugins which implement `org.apache.activemq.artemis.core.server.SecuritySettingPlugin`.
|
configured via a plugin which implements `org.apache.activemq.artemis.core.server.SecuritySettingPlugin` e.g.:
|
||||||
One or more plugins can be defined and configured alongside the normal XML, e.g.:
|
|
||||||
|
|
||||||
<security-settings>
|
<security-settings>
|
||||||
...
|
|
||||||
<security-setting-plugin class-name="org.apache.activemq.artemis.core.server.impl.LegacyLDAPSecuritySettingPlugin">
|
<security-setting-plugin class-name="org.apache.activemq.artemis.core.server.impl.LegacyLDAPSecuritySettingPlugin">
|
||||||
<setting name="initialContextFactory" value="com.sun.jndi.ldap.LdapCtxFactory"/>
|
<setting name="initialContextFactory" value="com.sun.jndi.ldap.LdapCtxFactory"/>
|
||||||
<setting name="connectionURL" value="ldap://localhost:1024"/>
|
<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`.
|
- `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
|
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
|
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
|
since the name of queue or topic coming from LDAP will server as the "match" for the security-setting the security-setting
|
||||||
|
@ -255,45 +256,11 @@ This is the default security manager.
|
||||||
- The flexible, pluggable `ActiveMQJAASSecurityManager` which supports any standard JAAS login module. Artemis ships
|
- The flexible, pluggable `ActiveMQJAASSecurityManager` which supports any standard JAAS login module. Artemis ships
|
||||||
with several login modules which will be discussed further down.
|
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
|
### JAAS Security Manager
|
||||||
|
|
||||||
When using JAAS much of the configuration depends on which login module is used. However, there are a few commonalities
|
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
|
for every case. The first place to look is in `bootstrap.xml`. Here is an example using the `PropertiesLogin` JAAS login
|
||||||
using the `PropertiesLogin` JAAS login module which reads user, password, and role information from properties files
|
module which reads user, password, and role information from properties files:
|
||||||
much like the non-JAAS security manager implementation:
|
|
||||||
|
|
||||||
<jaas-security domain="PropertiesLogin"/>
|
<jaas-security domain="PropertiesLogin"/>
|
||||||
|
|
||||||
|
|
|
@ -20,10 +20,8 @@ import javax.jms.ConnectionFactory;
|
||||||
import javax.management.MBeanServer;
|
import javax.management.MBeanServer;
|
||||||
import javax.management.MBeanServerFactory;
|
import javax.management.MBeanServerFactory;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.activemq.artemis.api.core.SimpleString;
|
import org.apache.activemq.artemis.api.core.SimpleString;
|
||||||
|
@ -98,20 +96,13 @@ public class OpenWireTestBase extends ActiveMQTestBase {
|
||||||
//guest cannot do anything
|
//guest cannot do anything
|
||||||
Role destRole = new Role("manager", false, false, false, false, true, true, false);
|
Role destRole = new Role("manager", false, false, false, false, true, true, false);
|
||||||
|
|
||||||
Map<String, Set<Role>> settings = server.getConfiguration().getSecurityRoles();
|
Set<Role> roles = new HashSet<>();
|
||||||
if (settings == null) {
|
roles.add(senderRole);
|
||||||
settings = new HashMap<>();
|
roles.add(receiverRole);
|
||||||
server.getConfiguration().setSecurityRoles(settings);
|
roles.add(guestRole);
|
||||||
}
|
roles.add(destRole);
|
||||||
Set<Role> anySet = settings.get("#");
|
|
||||||
if (anySet == null) {
|
server.getConfiguration().putSecurityRoles("#", roles);
|
||||||
anySet = new HashSet<>();
|
|
||||||
settings.put("#", anySet);
|
|
||||||
}
|
|
||||||
anySet.add(senderRole);
|
|
||||||
anySet.add(receiverRole);
|
|
||||||
anySet.add(guestRole);
|
|
||||||
anySet.add(destRole);
|
|
||||||
}
|
}
|
||||||
jmsServer = new JMSServerManagerImpl(server);
|
jmsServer = new JMSServerManagerImpl(server);
|
||||||
namingContext = new InVMNamingContext();
|
namingContext = new InVMNamingContext();
|
||||||
|
|
|
@ -172,7 +172,7 @@ public class LDAPSecurityTest extends AbstractLdapTestUnit {
|
||||||
ActiveMQServer server = getActiveMQServer();
|
ActiveMQServer server = getActiveMQServer();
|
||||||
Set<Role> roles = new HashSet<>();
|
Set<Role> roles = new HashSet<>();
|
||||||
roles.add(new Role("programmers", false, false, false, false, false, false, false));
|
roles.add(new Role("programmers", false, false, false, false, false, false, false));
|
||||||
server.getConfiguration().getSecurityRoles().put("#", roles);
|
server.getConfiguration().putSecurityRoles("#", roles);
|
||||||
server.start();
|
server.start();
|
||||||
server.createQueue(ADDRESS, DURABLE_QUEUE, null, true, false);
|
server.createQueue(ADDRESS, DURABLE_QUEUE, null, true, false);
|
||||||
server.createQueue(ADDRESS, NON_DURABLE_QUEUE, null, false, false);
|
server.createQueue(ADDRESS, NON_DURABLE_QUEUE, null, false, false);
|
||||||
|
@ -260,7 +260,7 @@ public class LDAPSecurityTest extends AbstractLdapTestUnit {
|
||||||
ActiveMQServer server = getActiveMQServer();
|
ActiveMQServer server = getActiveMQServer();
|
||||||
Set<Role> roles = new HashSet<>();
|
Set<Role> roles = new HashSet<>();
|
||||||
roles.add(new Role("admins", true, true, true, true, true, true, true));
|
roles.add(new Role("admins", true, true, true, true, true, true, true));
|
||||||
server.getConfiguration().getSecurityRoles().put("#", roles);
|
server.getConfiguration().putSecurityRoles("#", roles);
|
||||||
server.start();
|
server.start();
|
||||||
|
|
||||||
ClientSessionFactory cf = locator.createSessionFactory();
|
ClientSessionFactory cf = locator.createSessionFactory();
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -297,8 +297,7 @@ public class LegacyLDAPSecuritySettingPluginTest extends AbstractLdapTestUnit {
|
||||||
.setConnectionUsername("uid=admin,ou=system")
|
.setConnectionUsername("uid=admin,ou=system")
|
||||||
.setConnectionPassword("secret")
|
.setConnectionPassword("secret")
|
||||||
.setConnectionProtocol("s")
|
.setConnectionProtocol("s")
|
||||||
.setAuthentication("simple")
|
.setAuthentication("simple");
|
||||||
.populateSecurityRoles();
|
|
||||||
|
|
||||||
ActiveMQJAASSecurityManager securityManager = new ActiveMQJAASSecurityManager("LDAPLogin");
|
ActiveMQJAASSecurityManager securityManager = new ActiveMQJAASSecurityManager("LDAPLogin");
|
||||||
Configuration configuration = new ConfigurationImpl()
|
Configuration configuration = new ConfigurationImpl()
|
||||||
|
|
|
@ -229,7 +229,7 @@ public class SecurityTest extends ActiveMQTestBase {
|
||||||
ActiveMQServer server = addServer(ActiveMQServers.newActiveMQServer(createDefaultInVMConfig().setSecurityEnabled(true), ManagementFactory.getPlatformMBeanServer(), securityManager, false));
|
ActiveMQServer server = addServer(ActiveMQServers.newActiveMQServer(createDefaultInVMConfig().setSecurityEnabled(true), ManagementFactory.getPlatformMBeanServer(), securityManager, false));
|
||||||
Set<Role> roles = new HashSet<>();
|
Set<Role> roles = new HashSet<>();
|
||||||
roles.add(new Role("programmers", false, false, false, false, false, false, false));
|
roles.add(new Role("programmers", false, false, false, false, false, false, false));
|
||||||
server.getConfiguration().getSecurityRoles().put("#", roles);
|
server.getConfiguration().putSecurityRoles("#", roles);
|
||||||
server.start();
|
server.start();
|
||||||
server.createQueue(ADDRESS, DURABLE_QUEUE, null, true, false);
|
server.createQueue(ADDRESS, DURABLE_QUEUE, null, true, false);
|
||||||
server.createQueue(ADDRESS, NON_DURABLE_QUEUE, null, false, false);
|
server.createQueue(ADDRESS, NON_DURABLE_QUEUE, null, false, false);
|
||||||
|
@ -324,7 +324,7 @@ public class SecurityTest extends ActiveMQTestBase {
|
||||||
|
|
||||||
Set<Role> roles = new HashSet<>();
|
Set<Role> roles = new HashSet<>();
|
||||||
roles.add(new Role("programmers", false, false, false, false, false, false, false));
|
roles.add(new Role("programmers", false, false, false, false, false, false, false));
|
||||||
server.getConfiguration().getSecurityRoles().put("#", roles);
|
server.getConfiguration().putSecurityRoles("#", roles);
|
||||||
|
|
||||||
server.start();
|
server.start();
|
||||||
|
|
||||||
|
@ -418,7 +418,7 @@ public class SecurityTest extends ActiveMQTestBase {
|
||||||
ActiveMQServer server = addServer(ActiveMQServers.newActiveMQServer(createDefaultInVMConfig().setSecurityEnabled(true), ManagementFactory.getPlatformMBeanServer(), securityManager, false));
|
ActiveMQServer server = addServer(ActiveMQServers.newActiveMQServer(createDefaultInVMConfig().setSecurityEnabled(true), ManagementFactory.getPlatformMBeanServer(), securityManager, false));
|
||||||
Set<Role> roles = new HashSet<>();
|
Set<Role> roles = new HashSet<>();
|
||||||
roles.add(new Role("programmers", true, true, true, true, true, true, true));
|
roles.add(new Role("programmers", true, true, true, true, true, true, true));
|
||||||
server.getConfiguration().getSecurityRoles().put("#", roles);
|
server.getConfiguration().putSecurityRoles("#", roles);
|
||||||
server.start();
|
server.start();
|
||||||
|
|
||||||
ClientSessionFactory cf = createSessionFactory(locator);
|
ClientSessionFactory cf = createSessionFactory(locator);
|
||||||
|
@ -506,7 +506,7 @@ public class SecurityTest extends ActiveMQTestBase {
|
||||||
|
|
||||||
Set<Role> roles = new HashSet<>();
|
Set<Role> roles = new HashSet<>();
|
||||||
roles.add(new Role("programmers", true, true, true, true, true, true, true));
|
roles.add(new Role("programmers", true, true, true, true, true, true, true));
|
||||||
server.getConfiguration().getSecurityRoles().put("#", roles);
|
server.getConfiguration().putSecurityRoles("#", roles);
|
||||||
server.start();
|
server.start();
|
||||||
|
|
||||||
TransportConfiguration tc = new TransportConfiguration(NETTY_CONNECTOR_FACTORY);
|
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));
|
ActiveMQServer server = addServer(ActiveMQServers.newActiveMQServer(createDefaultInVMConfig().setSecurityEnabled(true), ManagementFactory.getPlatformMBeanServer(), securityManager, false));
|
||||||
Set<Role> roles = new HashSet<>();
|
Set<Role> roles = new HashSet<>();
|
||||||
roles.add(new Role("bar", true, true, true, true, true, true, true));
|
roles.add(new Role("bar", true, true, true, true, true, true, true));
|
||||||
server.getConfiguration().getSecurityRoles().put("#", roles);
|
server.getConfiguration().putSecurityRoles("#", roles);
|
||||||
server.start();
|
server.start();
|
||||||
|
|
||||||
ClientSessionFactory cf = createSessionFactory(locator);
|
ClientSessionFactory cf = createSessionFactory(locator);
|
||||||
|
|
Loading…
Reference in New Issue