This closes #325
This commit is contained in:
commit
8e4aca126b
|
@ -19,7 +19,6 @@ package org.apache.activemq.artemis.cli.commands;
|
|||
import java.io.File;
|
||||
|
||||
import io.airlift.airline.Command;
|
||||
import org.apache.activemq.artemis.dto.BrokerDTO;
|
||||
|
||||
@Command(name = "stop", description = "stops the broker instance")
|
||||
public class Stop extends Configurable {
|
||||
|
@ -27,9 +26,14 @@ public class Stop extends Configurable {
|
|||
@Override
|
||||
public Object execute(ActionContext context) throws Exception {
|
||||
super.execute(context);
|
||||
BrokerDTO broker = getBrokerDTO();
|
||||
|
||||
File file = broker.server.getConfigurationFile().getParentFile();
|
||||
String value = getConfiguration();
|
||||
|
||||
if (value != null && value.startsWith("xml:")) {
|
||||
value = value.substring("xml:".length());
|
||||
}
|
||||
|
||||
File file = new File(value).getParentFile();
|
||||
|
||||
File stopFile = new File(file, "STOP_ME");
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1144,6 +1144,12 @@ public class ConfigurationImpl implements Configuration, Serializable {
|
|||
return securitySettings;
|
||||
}
|
||||
|
||||
@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;
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,18 +301,32 @@ 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();
|
||||
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) {
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
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 destination = null;
|
||||
String destinationType = "unknown";
|
||||
|
@ -310,12 +383,158 @@ public class LegacyLDAPSecuritySettingPlugin implements SecuritySettingPlugin {
|
|||
securityRoles.put(destination, roles);
|
||||
}
|
||||
}
|
||||
|
||||
public SecuritySettingPlugin stop() {
|
||||
try {
|
||||
eventContext.close();
|
||||
}
|
||||
catch (Exception e) {
|
||||
ActiveMQServerLogger.LOGGER.errorPopulatingSecurityRolesFromLDAP(e);
|
||||
catch (NamingException e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
try {
|
||||
context.close();
|
||||
}
|
||||
catch (NamingException e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
this.securityRoles = securityRoles;
|
||||
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: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>
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
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);
|
||||
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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
||||
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
|
||||
|
@ -255,45 +256,11 @@ 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"/>
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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")
|
||||
.setConnectionPassword("secret")
|
||||
.setConnectionProtocol("s")
|
||||
.setAuthentication("simple")
|
||||
.populateSecurityRoles();
|
||||
.setAuthentication("simple");
|
||||
|
||||
ActiveMQJAASSecurityManager securityManager = new ActiveMQJAASSecurityManager("LDAPLogin");
|
||||
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));
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue