From bdfc1a4c2e5b906f249b4f3b2189335785e09a53 Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Thu, 17 May 2012 12:46:09 +0000 Subject: QPID-3997 : [Java Broker] add ability to configure multiple Authenticationmanagers and map different AuthenticationManagers to different ports git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1339578 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/configuration/ServerConfiguration.java | 21 +++ .../apache/qpid/server/plugins/PluginManager.java | 6 +- .../qpid/server/registry/ApplicationRegistry.java | 108 ++++++++--- .../qpid/server/registry/IApplicationRegistry.java | 2 +- .../manager/AnonymousAuthenticationManager.java | 205 +++++++++++++++++++++ .../PrincipalDatabaseAuthenticationManager.java | 5 +- .../qpid/server/AMQBrokerManagerMBeanTest.java | 1 - ...plicationRegistryAuthenticationManagerTest.java | 184 ++++++++++++++++++ .../registry/TestableApplicationRegistry.java | 48 +++++ .../AnonymousAuthenticationManagerTest.java | 109 +++++++++++ .../auth/rmi/RMIPasswordAuthenticatorTest.java | 5 +- .../qpid/server/util/InternalBrokerBaseCase.java | 10 +- .../qpid/server/util/TestApplicationRegistry.java | 8 +- .../MultipleAuthenticationManagersTest.java | 109 +++++++++++ qpid/java/test-profiles/CPPExcludes | 2 + 15 files changed, 781 insertions(+), 42 deletions(-) create mode 100644 qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AnonymousAuthenticationManager.java create mode 100644 qpid/java/broker/src/test/java/org/apache/qpid/server/registry/ApplicationRegistryAuthenticationManagerTest.java create mode 100644 qpid/java/broker/src/test/java/org/apache/qpid/server/registry/TestableApplicationRegistry.java create mode 100644 qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/AnonymousAuthenticationManagerTest.java create mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/MultipleAuthenticationManagersTest.java diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index 8ed87ec9be..0be4e682c9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -581,6 +581,27 @@ public class ServerConfiguration extends ConfigurationPlugin return getBooleanValue("security.msg-auth"); } + public String getDefaultAuthenticationManager() + { + return getStringValue("security.default-auth-manager"); + } + + + public Map getPortAuthenticationMappings() + { + String[] ports = getConfig().getStringArray("security.port-mappings.port-mapping.port"); + String[] authManagers = getConfig().getStringArray("security.port-mappings.port-mapping.auth-manager"); + + Map portMappings = new HashMap(); + for(int i = 0; i < ports.length; i++) + { + portMappings.put(Integer.valueOf(ports[i]), authManagers[i]); + } + + return portMappings; + } + + public String getManagementKeyStorePath() { final String fallback = getStringValue("management.ssl.keystorePath"); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java index 407ce57ad6..5c49752ede 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java @@ -22,6 +22,7 @@ import org.apache.commons.configuration.ConfigurationException; import org.apache.felix.framework.Felix; import org.apache.felix.framework.util.StringMap; import org.apache.log4j.Logger; +import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManager; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleException; @@ -156,7 +157,8 @@ public class PluginManager implements Closeable new SlowConsumerDetectionConfigurationFactory(), new SlowConsumerDetectionPolicyConfigurationFactory(), new SlowConsumerDetectionQueueConfigurationFactory(), - PrincipalDatabaseAuthenticationManager.PrincipalDatabaseAuthenticationManagerConfiguration.FACTORY)) + PrincipalDatabaseAuthenticationManager.PrincipalDatabaseAuthenticationManagerConfiguration.FACTORY, + AnonymousAuthenticationManager.AnonymousAuthenticationManagerConfiguration.FACTORY)) { _configPlugins.put(configFactory.getParentPaths(), configFactory); } @@ -172,7 +174,7 @@ public class PluginManager implements Closeable } for (AuthenticationManagerPluginFactory pluginFactory : Arrays.asList( - PrincipalDatabaseAuthenticationManager.FACTORY)) + PrincipalDatabaseAuthenticationManager.FACTORY, AnonymousAuthenticationManager.FACTORY)) { _authenticationManagerPlugins.put(pluginFactory.getPluginName(), pluginFactory); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index 36f1953053..61bbfce4a3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -20,6 +20,7 @@ */ package org.apache.qpid.server.registry; +import java.net.UnknownHostException; import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.Logger; import org.osgi.framework.BundleContext; @@ -61,13 +62,7 @@ import org.apache.qpid.server.virtualhost.VirtualHostRegistry; import java.net.InetSocketAddress; import java.net.SocketAddress; -import java.util.Collection; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Timer; -import java.util.TimerTask; -import java.util.UUID; +import java.util.*; import java.util.concurrent.atomic.AtomicReference; @@ -85,11 +80,14 @@ public abstract class ApplicationRegistry implements IApplicationRegistry private final ServerConfiguration _configuration; - private final Map _acceptors = new HashMap(); + private final Map _acceptors = + Collections.synchronizedMap(new HashMap()); private ManagedObjectRegistry _managedObjectRegistry; - private AuthenticationManager _authenticationManager; + private AuthenticationManager _defaultAuthenticationManager; + + private Map _authenticationManagers; private VirtualHostRegistry _virtualHostRegistry; @@ -127,6 +125,11 @@ public abstract class ApplicationRegistry implements IApplicationRegistry return _acceptors; } + private QpidAcceptor getAcceptor(SocketAddress address) + { + return _acceptors.get(address); + } + protected void setManagedObjectRegistry(ManagedObjectRegistry managedObjectRegistry) { _managedObjectRegistry = managedObjectRegistry; @@ -316,7 +319,10 @@ public abstract class ApplicationRegistry implements IApplicationRegistry _securityManager = new SecurityManager(_configuration, _pluginManager); - _authenticationManager = createAuthenticationManager(); + _authenticationManagers = createAuthenticationManagers(); + + // The default authentication manager is provided in the map associated with the null key + _defaultAuthenticationManager = _authenticationManagers.get(null); _managedObjectRegistry.start(); } @@ -342,14 +348,16 @@ public abstract class ApplicationRegistry implements IApplicationRegistry /** * Iterates across all discovered authentication manager factories, offering the security configuration to each. - * Expects exactly one authentication manager to configure and initialise itself. - * - * It is an error to configure more than one authentication manager, or to configure none. * - * @return authentication manager + * If more than one authentication manager is configured, one MUST be specified as the default + * + * It not to configure any authentication managers. + * + * @return map from port to authentication manager, with the null key being used to indicate the default. * @throws ConfigurationException */ - protected AuthenticationManager createAuthenticationManager() throws ConfigurationException + protected Map createAuthenticationManagers() + throws ConfigurationException, UnknownHostException { final SecurityConfiguration securityConfiguration = _configuration.getConfiguration(SecurityConfiguration.class.getName()); final Collection> factories = _pluginManager.getAuthenticationManagerPlugins().values(); @@ -360,31 +368,67 @@ public abstract class ApplicationRegistry implements IApplicationRegistry "manager plugin has been placed in the plugins directory."); } - AuthenticationManager authMgr = null; - + AuthenticationManager defaultAuthMgr; + + Map authManagersByClass = new HashMap(); for (final Iterator> iterator = factories.iterator(); iterator.hasNext();) { final AuthenticationManagerPluginFactory factory = (AuthenticationManagerPluginFactory) iterator.next(); final AuthenticationManager tmp = factory.newInstance(securityConfiguration); if (tmp != null) { - if (authMgr != null) + if(authManagersByClass.containsKey(tmp.getClass().getSimpleName())) { - throw new ConfigurationException("Cannot configure more than one authentication manager." - + " Both " + tmp.getClass() + " and " + authMgr.getClass() + " are configured." - + " Remove configuration for one of the authentication manager, or remove the plugin JAR" - + " from the classpath."); + throw new ConfigurationException("Cannot configure more than one authentication manager of type" + + tmp.getClass().getSimpleName() + "." + + " Remove configuration for one of the authentication managers."); } - authMgr = tmp; + authManagersByClass.put(tmp.getClass().getSimpleName(),tmp); } + } - if (authMgr == null) + if(authManagersByClass.isEmpty()) { throw new ConfigurationException("No authentication managers configured within the configure file."); } + if(authManagersByClass.size() == 1) + { + defaultAuthMgr = authManagersByClass.values().iterator().next(); + } + else if(!authManagersByClass.isEmpty() && _configuration.getDefaultAuthenticationManager() != null) + { + defaultAuthMgr = authManagersByClass.get(_configuration.getDefaultAuthenticationManager()); + if(defaultAuthMgr == null) + { + throw new ConfigurationException("No authentication managers configured of type " + + _configuration.getDefaultAuthenticationManager() + + " which is specified as the default. Available managers are: " + + authManagersByClass.keySet()); + } + } + else + { + throw new ConfigurationException("If more than one authentication manager is configured a default MUST be specified."); + } + + Map authManagers = new HashMap(); + authManagers .put(null, defaultAuthMgr); + String host = _configuration.getBind(); + + for(Map.Entry portMapping : _configuration.getPortAuthenticationMappings().entrySet()) + { + + AuthenticationManager authenticationManager = authManagersByClass.get(portMapping.getValue()); + if(authenticationManager == null) + { + throw new ConfigurationException("Unknown authentication manager class " + portMapping.getValue() + + " configured for port " + portMapping.getKey()); + } + authManagers.put(portMapping.getKey(), authenticationManager); + } - return authMgr; + return authManagers; } protected void initialiseVirtualHosts() throws Exception @@ -541,7 +585,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry //Shutdown virtualhosts close(_virtualHostRegistry); - close(_authenticationManager); + close(_defaultAuthenticationManager); close(_qmfService); @@ -613,19 +657,25 @@ public abstract class ApplicationRegistry implements IApplicationRegistry return _managedObjectRegistry; } - public AuthenticationManager getAuthenticationManager() + public AuthenticationManager getDefaultAuthenticationManager() { - return _authenticationManager; + return _defaultAuthenticationManager; } @Override public AuthenticationManager getAuthenticationManager(SocketAddress address) { - return _authenticationManager; + AuthenticationManager authManager = + address instanceof InetSocketAddress + ? _authenticationManagers.get(((InetSocketAddress)address).getPort()) + : null; + + return authManager == null ? _defaultAuthenticationManager : authManager; } + public PluginManager getPluginManager() { return _pluginManager; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java index af2f0d78bc..42a4927555 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java @@ -70,7 +70,7 @@ public interface IApplicationRegistry extends StatisticsGatherer * * @return the AuthenticationManager */ - AuthenticationManager getAuthenticationManager(); + AuthenticationManager getDefaultAuthenticationManager(); /** * Get the AuthenticationManager for the given socket address diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AnonymousAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AnonymousAuthenticationManager.java new file mode 100644 index 0000000000..1a6515f71f --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AnonymousAuthenticationManager.java @@ -0,0 +1,205 @@ +/* + * 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.qpid.server.security.auth.manager; + +import java.security.Principal; +import java.util.Arrays; +import java.util.List; +import javax.security.auth.Subject; +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.log4j.Logger; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; +import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; +import org.apache.qpid.server.security.auth.AuthenticationResult; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; +import org.apache.qpid.server.security.auth.sasl.anonymous.AnonymousInitialiser; +import org.apache.qpid.server.security.auth.sasl.anonymous.AnonymousSaslServer; + +public class AnonymousAuthenticationManager implements AuthenticationManager +{ + private static final Logger _logger = Logger.getLogger(AnonymousAuthenticationManager.class); + + private static final AnonymousInitialiser SASL_INITIALISER = new AnonymousInitialiser(); + + private static final String ANONYMOUS = SASL_INITIALISER.getMechanismName(); + + private static final Principal ANONYMOUS_PRINCIPAL = new UsernamePrincipal("ANONYMOUS"); + + private static final Subject ANONYMOUS_SUBJECT = new Subject(); + static + { + ANONYMOUS_SUBJECT.getPrincipals().add(ANONYMOUS_PRINCIPAL); + } + + private static final AuthenticationResult ANONYMOUS_AUTHENTICATION = new AuthenticationResult(ANONYMOUS_SUBJECT); + + + private static CallbackHandler _callbackHandler = SASL_INITIALISER.getCallbackHandler(); + + static final AnonymousAuthenticationManager INSTANCE = new AnonymousAuthenticationManager(); + + public static class AnonymousAuthenticationManagerConfiguration extends ConfigurationPlugin + { + + public static final ConfigurationPluginFactory FACTORY = + new ConfigurationPluginFactory() + { + public List getParentPaths() + { + return Arrays.asList("security.anonymous-auth-manager"); + } + + public ConfigurationPlugin newInstance(final String path, final Configuration config) throws ConfigurationException + { + final ConfigurationPlugin instance = new AnonymousAuthenticationManagerConfiguration(); + + instance.setConfiguration(path, config); + return instance; + } + }; + + public String[] getElementsProcessed() + { + return new String[0]; + } + + public void validateConfiguration() throws ConfigurationException + { + } + + } + + + public static final AuthenticationManagerPluginFactory FACTORY = new AuthenticationManagerPluginFactory() + { + public AnonymousAuthenticationManager newInstance(final ConfigurationPlugin config) throws ConfigurationException + { + AnonymousAuthenticationManagerConfiguration configuration = + config == null + ? null + : (AnonymousAuthenticationManagerConfiguration) config.getConfiguration(AnonymousAuthenticationManagerConfiguration.class.getName()); + + // If there is no configuration for this plugin then don't load it. + if (configuration == null) + { + _logger.info("No authentication-manager configuration found for AnonymousAuthenticationManager"); + return null; + } + return INSTANCE; + } + + public Class getPluginClass() + { + return AnonymousAuthenticationManager.class; + } + + public String getPluginName() + { + return AnonymousAuthenticationManager.class.getName(); + } + }; + + + private AnonymousAuthenticationManager() + { + } + + @Override + public void initialise() + { + + } + + @Override + public String getMechanisms() + { + return ANONYMOUS; + } + + @Override + public SaslServer createSaslServer(String mechanism, String localFQDN) throws SaslException + { + if(ANONYMOUS.equals(mechanism)) + { + return new AnonymousSaslServer(); + } + else + { + throw new SaslException("Unknown mechanism: " + mechanism); + } + } + + @Override + public AuthenticationResult authenticate(SaslServer server, byte[] response) + { + try + { + // Process response from the client + byte[] challenge = server.evaluateResponse(response != null ? response : new byte[0]); + + if (server.isComplete()) + { + return ANONYMOUS_AUTHENTICATION; + } + else + { + return new AuthenticationResult(challenge, AuthenticationResult.AuthenticationStatus.CONTINUE); + } + } + catch (SaslException e) + { + return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR, e); + } + } + + @Override + public AuthenticationResult authenticate(String username, String password) + { + return ANONYMOUS_AUTHENTICATION; + } + + @Override + public CallbackHandler getHandler(String mechanism) + { + if(ANONYMOUS.equals(mechanism)) + { + return _callbackHandler; + } + else + { + return null; + } + } + + @Override + public void close() + { + } + + @Override + public void configure(ConfigurationPlugin config) throws ConfigurationException + { + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java index 8b6551262d..b34e6acc6d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java @@ -103,7 +103,10 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan { public PrincipalDatabaseAuthenticationManager newInstance(final ConfigurationPlugin config) throws ConfigurationException { - final PrincipalDatabaseAuthenticationManagerConfiguration configuration = config.getConfiguration(PrincipalDatabaseAuthenticationManagerConfiguration.class.getName()); + final PrincipalDatabaseAuthenticationManagerConfiguration configuration = + config == null + ? null + : (PrincipalDatabaseAuthenticationManagerConfiguration) config.getConfiguration(PrincipalDatabaseAuthenticationManagerConfiguration.class.getName()); // If there is no configuration for this plugin then don't load it. if (configuration == null) diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java index 5c500771c2..d26e286c90 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java @@ -36,7 +36,6 @@ import org.apache.qpid.server.queue.AMQQueueFactory; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.registry.IApplicationRegistry; -import org.apache.qpid.server.store.TestableMemoryMessageStore; import org.apache.qpid.server.store.TestableMemoryMessageStoreFactory; import org.apache.qpid.server.util.TestApplicationRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/registry/ApplicationRegistryAuthenticationManagerTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/registry/ApplicationRegistryAuthenticationManagerTest.java new file mode 100644 index 0000000000..7fd608450a --- /dev/null +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/registry/ApplicationRegistryAuthenticationManagerTest.java @@ -0,0 +1,184 @@ +/* + * 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.qpid.server.registry; + +import java.net.InetSocketAddress; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManager; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; +import org.apache.qpid.server.util.InternalBrokerBaseCase; + +public class ApplicationRegistryAuthenticationManagerTest extends InternalBrokerBaseCase +{ + private Runnable _configureTask; + + @Override + public void tearDown() throws Exception + { + _configureTask = null; + super.tearDown(); + } + + @Override + protected void createBroker() throws Exception + { + // Do nothing - we don't want create broker called in setUp + } + + @Override + protected void configure() + { + if(_configureTask != null) + { + _configureTask.run(); + } + } + + @Override + protected IApplicationRegistry createApplicationRegistry() throws ConfigurationException + { + return new TestableApplicationRegistry(getConfiguration()); + } + + private void reallyCreateBroker() throws Exception + { + super.createBroker(); + } + + public void testNoAuthenticationManagers() throws Exception + { + try + { + reallyCreateBroker(); + fail("Expected a ConfigurationException when no AuthenticationManagers are defined"); + } + catch(ConfigurationException e) + { + // pass + } + } + + public void testSingleAuthenticationManager() throws Exception + { + _configureTask = + new Runnable() + { + @Override + public void run() + { + getConfiguration().getConfig().addProperty("security.anonymous-auth-manager", ""); + } + }; + + try + { + reallyCreateBroker(); + } + catch(ConfigurationException e) + { + fail("Unexpected ConfigurationException when creating the registry with a single AuthenticationManager"); + } + } + + public void testMultipleAuthenticationManagersNoDefault() throws Exception + { + _configureTask = + new Runnable() + { + @Override + public void run() + { + getConfiguration().getConfig().addProperty("security.anonymous-auth-manager", ""); + getConfiguration().getConfig().addProperty("security.pd-auth-manager.principal-database.class","org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase"); + } + }; + try + { + reallyCreateBroker(); + fail("Expected ConfigurationException as two AuthenticationManagers are defined, but there is no default specified"); + } + catch (ConfigurationException e) + { + // pass + } + } + + public void testDefaultAuthenticationManager() throws Exception + { + _configureTask = + new Runnable() + { + @Override + public void run() + { + getConfiguration().getConfig().addProperty("security.anonymous-auth-manager", ""); + getConfiguration().getConfig().addProperty("security.pd-auth-manager.principal-database.class","org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase"); + getConfiguration().getConfig().addProperty("security.default-auth-manager", "AnonymousAuthenticationManager"); + } + }; + try + { + reallyCreateBroker(); + } + catch (ConfigurationException e) + { + fail("Unexpected ConfigurationException when two AuthenticationManagers are defined, but there is a default specified"); + } + + AuthenticationManager authMgr = + ApplicationRegistry.getInstance().getAuthenticationManager(new InetSocketAddress(1)); + + assertNotNull("AuthenticationManager should not be null for any socket", authMgr); + assertEquals("AuthenticationManager not of expected class", AnonymousAuthenticationManager.class, authMgr.getClass()); + + + } + + public void testMappedAuthenticationManager() throws Exception + { + _configureTask = + new Runnable() + { + @Override + public void run() + { + getConfiguration().getConfig().addProperty("security.anonymous-auth-manager", ""); + getConfiguration().getConfig().addProperty("security.pd-auth-manager.principal-database.class","org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase"); + getConfiguration().getConfig().addProperty("security.default-auth-manager", "PrincipalDatabaseAuthenticationManager"); + getConfiguration().getConfig().addProperty("security.port-mappings.port-mapping.port", "200"); + getConfiguration().getConfig().addProperty("security.port-mappings.port-mapping.auth-manager", "AnonymousAuthenticationManager"); + } + }; + reallyCreateBroker(); + + AuthenticationManager authMgr = + ApplicationRegistry.getInstance().getAuthenticationManager(new InetSocketAddress(200)); + + assertNotNull("AuthenticationManager should not be null for any socket", authMgr); + assertEquals("AuthenticationManager not of expected class", AnonymousAuthenticationManager.class, authMgr.getClass()); + + // test the default is still in effect for other ports + authMgr = ApplicationRegistry.getInstance().getAuthenticationManager(new InetSocketAddress(1)); + assertEquals("AuthenticationManager not of expected class", PrincipalDatabaseAuthenticationManager.class, authMgr.getClass()); + + + } +} diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/registry/TestableApplicationRegistry.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/registry/TestableApplicationRegistry.java new file mode 100644 index 0000000000..db7a7f7950 --- /dev/null +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/registry/TestableApplicationRegistry.java @@ -0,0 +1,48 @@ +/* + * 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.qpid.server.registry; + +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.configuration.ServerConfiguration; +import org.apache.qpid.server.logging.NullRootMessageLogger; +import org.apache.qpid.server.logging.actors.BrokerActor; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.actors.GenericActor; + +class TestableApplicationRegistry extends ApplicationRegistry +{ + + public TestableApplicationRegistry(ServerConfiguration config) throws ConfigurationException + { + super(config); + } + + @Override + public void initialise() throws Exception + { + CurrentActor.setDefault(new BrokerActor(new NullRootMessageLogger())); + GenericActor.setDefaultMessageLogger(new NullRootMessageLogger()); + super.initialise(); + } + + + +} + + diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/AnonymousAuthenticationManagerTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/AnonymousAuthenticationManagerTest.java new file mode 100644 index 0000000000..eecde964a3 --- /dev/null +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/AnonymousAuthenticationManagerTest.java @@ -0,0 +1,109 @@ +/* + * 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.qpid.server.security.auth.manager; + +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; +import org.apache.commons.configuration.CompositeConfiguration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.XMLConfiguration; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; +import org.apache.qpid.server.security.auth.AuthenticationResult; +import org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase; +import org.apache.qpid.server.util.InternalBrokerBaseCase; + +public class AnonymousAuthenticationManagerTest extends InternalBrokerBaseCase +{ + + private AuthenticationManager _manager = null; + + public void setUp() throws Exception + { + _manager = AnonymousAuthenticationManager.INSTANCE; + } + + + public void tearDown() throws Exception + { + if(_manager != null) + { + _manager = null; + } + } + + private ConfigurationPlugin getPlainDatabaseConfig() throws ConfigurationException + { + final ConfigurationPlugin config = new PrincipalDatabaseAuthenticationManager.PrincipalDatabaseAuthenticationManagerConfiguration(); + + XMLConfiguration xmlconfig = new XMLConfiguration(); + xmlconfig.addProperty("pd-auth-manager.principal-database.class", PlainPasswordFilePrincipalDatabase.class.getName()); + + // Create a CompositeConfiguration as this is what the broker uses + CompositeConfiguration composite = new CompositeConfiguration(); + composite.addConfiguration(xmlconfig); + config.setConfiguration("security", xmlconfig); + return config; + } + + + public void testConfiguration() throws Exception + { + AuthenticationManager authenticationManager = + AnonymousAuthenticationManager.FACTORY.newInstance(getPlainDatabaseConfig()); + + assertNull("AnonymousAuthenticationManager unexpectedly created when not in config", authenticationManager); + } + + public void testGetMechanisms() throws Exception + { + assertEquals("ANONYMOUS", _manager.getMechanisms()); + } + + public void testCreateSaslServer() throws Exception + { + SaslServer server = _manager.createSaslServer("ANONYMOUS", "example.example.com"); + + assertEquals("Sasl Server mechanism name is not as expected", "ANONYMOUS", server.getMechanismName()); + + try + { + server = _manager.createSaslServer("PLAIN", "example.example.com"); + fail("Expected creating SaslServer with incorrect mechanism to throw an exception"); + } + catch (SaslException e) + { + // pass + } + } + + public void testAuthenticate() throws Exception + { + SaslServer saslServer = _manager.createSaslServer("ANONYMOUS", "example.example.com"); + AuthenticationResult result = _manager.authenticate(saslServer, new byte[0]); + assertNotNull(result); + assertEquals("Expected authentication to be successful", + AuthenticationResult.AuthenticationStatus.SUCCESS, + result.getStatus()); + assertNotNull("Subject should not be null", result.getSubject()); + } + + +} diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticatorTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticatorTest.java index bef03057ec..584f3d1358 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticatorTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticatorTest.java @@ -20,6 +20,7 @@ */ package org.apache.qpid.server.security.auth.rmi; +import java.util.Map; import junit.framework.TestCase; import org.apache.commons.configuration.ConfigurationException; @@ -126,9 +127,9 @@ public class RMIPasswordAuthenticatorTest extends TestCase TestApplicationRegistry reg = new TestApplicationRegistry(serverConfig) { @Override - protected AuthenticationManager createAuthenticationManager() throws ConfigurationException + protected Map createAuthenticationManagers() throws ConfigurationException { - return null; + return Collections.emptyMap(); } }; ApplicationRegistry.initialise(reg); diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/util/InternalBrokerBaseCase.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/util/InternalBrokerBaseCase.java index 8a34e92985..f8200bf1cd 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/util/InternalBrokerBaseCase.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/util/InternalBrokerBaseCase.java @@ -20,8 +20,7 @@ */ package org.apache.qpid.server.util; -import java.util.UUID; - +import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.XMLConfiguration; import org.apache.qpid.AMQException; @@ -85,7 +84,7 @@ public class InternalBrokerBaseCase extends QpidTestCase configure(); - _registry = new TestApplicationRegistry(_configuration); + _registry = createApplicationRegistry(); ApplicationRegistry.initialise(_registry); _registry.getVirtualHostRegistry().setDefaultVirtualHostName(getName()); _virtualHost = _registry.getVirtualHostRegistry().getVirtualHost(getName()); @@ -119,6 +118,11 @@ public class InternalBrokerBaseCase extends QpidTestCase _session.addChannel(_channel); } + protected IApplicationRegistry createApplicationRegistry() throws ConfigurationException + { + return new TestApplicationRegistry(_configuration); + } + protected void configure() { // Allow other tests to override configuration diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java index 7aa5ed23fe..6e18718478 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java @@ -20,6 +20,8 @@ */ package org.apache.qpid.server.util; +import java.util.Collections; +import java.util.Map; import org.apache.commons.configuration.ConfigurationException; import org.apache.qpid.server.configuration.ServerConfiguration; @@ -52,10 +54,10 @@ public class TestApplicationRegistry extends ApplicationRegistry } /** - * @see org.apache.qpid.server.registry.ApplicationRegistry#createAuthenticationManager() + * @see org.apache.qpid.server.registry.ApplicationRegistry#createAuthenticationManagers() */ @Override - protected AuthenticationManager createAuthenticationManager() throws ConfigurationException + protected Map createAuthenticationManagers() throws ConfigurationException { final Properties users = new Properties(); users.put("guest","guest"); @@ -86,7 +88,7 @@ public class TestApplicationRegistry extends ApplicationRegistry pdam.initialise(); - return pdam; + return Collections.singletonMap(null,pdam); } } diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/MultipleAuthenticationManagersTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/MultipleAuthenticationManagersTest.java new file mode 100644 index 0000000000..858b32c24c --- /dev/null +++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/MultipleAuthenticationManagersTest.java @@ -0,0 +1,109 @@ +/* + * 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.qpid.server.security.auth.manager; + +import javax.jms.Connection; +import javax.jms.JMSException; +import org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +public class MultipleAuthenticationManagersTest extends QpidBrokerTestCase +{ + private static final String KEYSTORE = "test-profiles/test_resources/ssl/java_client_keystore.jks"; + private static final String KEYSTORE_PASSWORD = "password"; + private static final String TRUSTSTORE = "test-profiles/test_resources/ssl/java_client_truststore.jks"; + private static final String TRUSTSTORE_PASSWORD = "password"; + + @Override + protected void setUp() throws Exception + { + setConfigurationProperty("connector.ssl.enabled", "true"); + setConfigurationProperty("connector.ssl.sslOnly", "false"); + setConfigurationProperty("security.anonymous-auth-manager", ""); + setConfigurationProperty("security.default-auth-manager", "PrincipalDatabaseAuthenticationManager"); + setConfigurationProperty("security.port-mappings.port-mapping.port", String.valueOf(QpidBrokerTestCase.DEFAULT_SSL_PORT)); + setConfigurationProperty("security.port-mappings.port-mapping.auth-manager", "AnonymousAuthenticationManager"); + + // set the ssl system properties + setSystemProperty("javax.net.ssl.keyStore", KEYSTORE); + setSystemProperty("javax.net.ssl.keyStorePassword", KEYSTORE_PASSWORD); + setSystemProperty("javax.net.ssl.trustStore", TRUSTSTORE); + setSystemProperty("javax.net.ssl.trustStorePassword", TRUSTSTORE_PASSWORD); + setSystemProperty("javax.net.debug", "ssl"); + super.setUp(); + } + + private Connection getAnonymousSSLConnection() throws Exception + { + String url = "amqp://:@test/?brokerlist='tcp://localhost:%s?ssl='true''"; + + url = String.format(url,QpidBrokerTestCase.DEFAULT_SSL_PORT); + + return new AMQConnection(url); + + } + + private Connection getAnonymousConnection() throws Exception + { + String url = "amqp://:@test/?brokerlist='tcp://localhost:%s'"; + + url = String.format(url,QpidBrokerTestCase.DEFAULT_PORT); + + return new AMQConnection(url); + + } + + + public void testMultipleAuthenticationManagers() throws Exception + { + try + { + Connection conn = getConnection(); + assertNotNull("Connection unexpectedly null", conn); + } + catch(JMSException e) + { + fail("Should be able to create a connection with credentials to the standard port. " + e.getMessage()); + } + + try + { + Connection conn = getAnonymousSSLConnection(); + assertNotNull("Connection unexpectedly null", conn); + } + catch(JMSException e) + { + fail("Should be able to create a anonymous connection to the SSL port. " + e.getMessage()); + } + + try + { + Connection conn = getAnonymousConnection(); + fail("Should not be able to create anonymous connection to the standard port"); + } + catch(AMQException e) + { + // pass + } + + } +} diff --git a/qpid/java/test-profiles/CPPExcludes b/qpid/java/test-profiles/CPPExcludes index a8315cbb59..3fb6b63b6f 100755 --- a/qpid/java/test-profiles/CPPExcludes +++ b/qpid/java/test-profiles/CPPExcludes @@ -140,6 +140,7 @@ org.apache.qpid.info.systest.InfoPluginTest#* org.apache.qpid.info.test.* org.apache.qpid.server.security.access.* org.apache.qpid.server.security.access.plugins.* +org.apache.qpid.server.security.auth.manager.* org.apache.qpid.server.security.acl.* org.apache.qpid.server.configuration.* org.apache.qpid.server.configuration.plugins.* @@ -157,6 +158,7 @@ org.apache.qpid.server.logging.management.LoggingManagementMBeanTest#* org.apache.qpid.server.management.AMQUserManagementMBeanTest#* org.apache.qpid.server.SupportedProtocolVersionsTest#* + // QPID-3133: On 0-10, the exception listener is currently not invoked when reconnection fails to occurs. org.apache.qpid.server.failover.FailoverMethodTest#* -- cgit v1.2.1