From 532bc2b78fb4a136fe035d68e3146ec7b2fa40aa Mon Sep 17 00:00:00 2001 From: Alex Rudyy Date: Wed, 17 Apr 2013 10:53:55 +0000 Subject: QPID-4746, QPID-4747: remove the defaultAuthenticationProvider attribute from broker and add an overriding authentication provider for management mode git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1468830 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/server/BrokerOptionsTest.java | 6 + .../test/java/org/apache/qpid/server/MainTest.java | 22 ++ .../configuration/startup/BrokerRecovererTest.java | 91 +------- .../startup/DefaultRecovererProviderTest.java | 3 +- .../store/ConfigurationEntryStoreTestCase.java | 2 - .../qpid/server/model/BrokerShutdownTest.java | 3 +- .../qpid/server/model/adapter/PortFactoryTest.java | 11 +- .../auth/database/PropertiesPrincipalDatabase.java | 160 ------------- .../auth/jmx/JMXPasswordAuthenticatorTest.java | 259 +++++++++++++++++++++ .../manager/SimpleAuthenticationManagerTest.java | 140 +++++++++++ .../auth/rmi/RMIPasswordAuthenticatorTest.java | 258 -------------------- .../auth/sasl/CRAMMD5HexInitialiserTest.java | 109 +++++---- .../qpid/server/security/auth/sasl/SaslUtil.java | 85 +++++++ .../apache/qpid/server/util/StringUtilTest.java | 38 +++ 14 files changed, 626 insertions(+), 561 deletions(-) delete mode 100644 qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java create mode 100644 qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/jmx/JMXPasswordAuthenticatorTest.java create mode 100644 qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/SimpleAuthenticationManagerTest.java delete mode 100644 qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticatorTest.java create mode 100644 qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/SaslUtil.java create mode 100644 qpid/java/broker/src/test/java/org/apache/qpid/server/util/StringUtilTest.java (limited to 'qpid/java/broker/src/test') diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/BrokerOptionsTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/BrokerOptionsTest.java index c1acf81a1a..08031c36a4 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/BrokerOptionsTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/BrokerOptionsTest.java @@ -220,4 +220,10 @@ public class BrokerOptionsTest extends QpidTestCase _options.setOverwriteConfigurationStore(true); assertTrue(_options.isOverwriteConfigurationStore()); } + + public void testManagementModePassword() + { + _options.setManagementModePassword("test"); + assertEquals("Unexpected management mode password", "test", _options.getManagementModePassword()); + } } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/MainTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/MainTest.java index aab919a828..d7579e2b2a 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/MainTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/MainTest.java @@ -171,6 +171,28 @@ public class MainTest extends QpidTestCase assertEquals(0, options.getManagementModeHttpPort()); } + public void testManagementModePassword() + { + String password = getTestName(); + BrokerOptions options = startDummyMain("-mm -mmpass " + password); + assertTrue(options.isManagementMode()); + assertEquals(password, options.getManagementModePassword()); + + options = startDummyMain("-mm --management-mode-password " + password); + assertTrue(options.isManagementMode()); + assertEquals(password, options.getManagementModePassword()); + + options = startDummyMain("-mmpass " + password); + assertNotNull(options.getManagementModePassword()); + } + + public void testDefaultManagementModePassword() + { + BrokerOptions options = startDummyMain("-mm"); + assertTrue(options.isManagementMode()); + assertNotNull(options.getManagementModePassword()); + } + private BrokerOptions startDummyMain(String commandLine) { return (new TestMain(commandLine.split("\\s"))).getOptions(); diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/startup/BrokerRecovererTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/startup/BrokerRecovererTest.java index 3a41b61961..5a8580fd26 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/startup/BrokerRecovererTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/startup/BrokerRecovererTest.java @@ -20,10 +20,8 @@ */ package org.apache.qpid.server.configuration.startup; -import static org.mockito.Mockito.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import static org.mockito.Mockito.verify; import java.util.Arrays; import java.util.Collection; @@ -35,9 +33,9 @@ import java.util.UUID; import junit.framework.TestCase; +import org.apache.qpid.server.BrokerOptions; import org.apache.qpid.server.configuration.ConfigurationEntry; import org.apache.qpid.server.configuration.ConfiguredObjectRecoverer; -import org.apache.qpid.server.configuration.IllegalConfigurationException; import org.apache.qpid.server.configuration.RecovererProvider; import org.apache.qpid.server.logging.LogRecorder; import org.apache.qpid.server.logging.RootMessageLogger; @@ -73,7 +71,7 @@ public class BrokerRecovererTest extends TestCase super.setUp(); _brokerRecoverer = new BrokerRecoverer(mock(AuthenticationProviderFactory.class), mock(PortFactory.class), mock(StatisticsGatherer.class), - mock(VirtualHostRegistry.class), mock(LogRecorder.class), mock(RootMessageLogger.class), mock(TaskExecutor.class)); + mock(VirtualHostRegistry.class), mock(LogRecorder.class), mock(RootMessageLogger.class), mock(TaskExecutor.class), mock(BrokerOptions.class)); when(_brokerEntry.getId()).thenReturn(_brokerId); when(_brokerEntry.getChildren()).thenReturn(_brokerEntryChildren); @@ -89,7 +87,6 @@ public class BrokerRecovererTest extends TestCase { Map attributes = new HashMap(); attributes.put(Broker.DEFAULT_VIRTUAL_HOST, "test"); - attributes.put(Broker.DEFAULT_AUTHENTICATION_PROVIDER, "authenticationProvider1"); attributes.put(Broker.QUEUE_ALERT_THRESHOLD_MESSAGE_AGE, 9l); attributes.put(Broker.QUEUE_ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES, 8l); attributes.put(Broker.QUEUE_ALERT_THRESHOLD_QUEUE_DEPTH_BYTES, 7l); @@ -172,24 +169,6 @@ public class BrokerRecovererTest extends TestCase assertEquals(Collections.singletonList(port), broker.getPorts()); } - public void testCreateBrokerWithoutAuthenticationProviderThrowsException() - { - assertNotNull("expected to remove the base entry", _brokerEntryChildren.remove(AuthenticationProvider.class.getSimpleName())); - assertTrue("should be empty", _brokerEntryChildren.isEmpty()); - - RecovererProvider recovererProvider = createRecoveryProvider(new ConfigurationEntry[0], new ConfiguredObject[0]); - - try - { - _brokerRecoverer.create(recovererProvider, _brokerEntry); - fail("should have thrown an exception due to missing authentication provider configuration"); - } - catch(IllegalConfigurationException e) - { - //expected - } - } - public void testCreateBrokerWithOneAuthenticationProvider() { RecovererProvider recovererProvider = createRecoveryProvider(new ConfigurationEntry[]{_authenticationProviderEntry1}, @@ -202,29 +181,6 @@ public class BrokerRecovererTest extends TestCase assertEquals(Collections.singletonList(_authenticationProvider1), broker.getAuthenticationProviders()); } - public void testCreateBrokerWithMultipleAuthenticationProvidersAndNoDefaultThrowsException() - { - AuthenticationProvider authenticationProvider2 = mock(AuthenticationProvider.class); - when(authenticationProvider2.getName()).thenReturn("authenticationProvider2"); - ConfigurationEntry authenticationProviderEntry2 = mock(ConfigurationEntry.class); - _brokerEntryChildren.put(AuthenticationProvider.class.getSimpleName(), Arrays.asList(_authenticationProviderEntry1, authenticationProviderEntry2)); - - Map emptyBrokerAttributes = new HashMap(); - when(_brokerEntry.getAttributes()).thenReturn(emptyBrokerAttributes); - - RecovererProvider recovererProvider = createRecoveryProvider(new ConfigurationEntry[]{authenticationProviderEntry2, _authenticationProviderEntry1}, - new ConfiguredObject[]{authenticationProvider2, _authenticationProvider1}); - try - { - _brokerRecoverer.create(recovererProvider, _brokerEntry); - fail("should have thrown an exception due to missing authentication provider default"); - } - catch(IllegalConfigurationException e) - { - //expected - } - } - public void testCreateBrokerWithMultipleAuthenticationProvidersAndPorts() { //Create a second authentication provider @@ -233,13 +189,10 @@ public class BrokerRecovererTest extends TestCase ConfigurationEntry authenticationProviderEntry2 = mock(ConfigurationEntry.class); _brokerEntryChildren.put(AuthenticationProvider.class.getSimpleName(), Arrays.asList(_authenticationProviderEntry1, authenticationProviderEntry2)); - //Set the default authentication provider Map brokerAtttributes = new HashMap(); when(_brokerEntry.getAttributes()).thenReturn(brokerAtttributes); - brokerAtttributes.put(Broker.DEFAULT_AUTHENTICATION_PROVIDER, "authenticationProvider2"); - //Add a couple ports, one with a defined authentication provider and - //one without (which should then use the default) + //Add a couple ports ConfigurationEntry portEntry1 = mock(ConfigurationEntry.class); Port port1 = mock(Port.class); when(port1.getName()).thenReturn("port1"); @@ -249,6 +202,7 @@ public class BrokerRecovererTest extends TestCase Port port2 = mock(Port.class); when(port2.getName()).thenReturn("port2"); when(port2.getPort()).thenReturn(5672); + when(port2.getAttribute(Port.AUTHENTICATION_PROVIDER)).thenReturn("authenticationProvider2"); _brokerEntryChildren.put(Port.class.getSimpleName(), Arrays.asList(portEntry1, portEntry2)); RecovererProvider recovererProvider = createRecoveryProvider( @@ -258,47 +212,12 @@ public class BrokerRecovererTest extends TestCase Broker broker = _brokerRecoverer.create(recovererProvider, _brokerEntry); assertNotNull(broker); - assertEquals("Unexpected number of authentication providers", 2,broker.getAuthenticationProviders().size()); + assertEquals("Unexpected number of authentication providers", 2, broker.getAuthenticationProviders().size()); Collection ports = broker.getPorts(); assertEquals("Unexpected number of ports", 2, ports.size()); assertTrue(ports.contains(port1)); assertTrue(ports.contains(port2)); - - verify(port1).setAuthenticationProvider(any(AuthenticationProvider.class)); - verify(port1).setAuthenticationProvider(_authenticationProvider1); - - verify(port2).setAuthenticationProvider(any(AuthenticationProvider.class)); - verify(port2).setAuthenticationProvider(authenticationProvider2); - } - - public void testCreateBrokerAssignsGroupAccessorToAuthenticationProviders() - { - //Create a second authentication provider - AuthenticationProvider authenticationProvider2 = mock(AuthenticationProvider.class); - when(authenticationProvider2.getName()).thenReturn("authenticationProvider2"); - ConfigurationEntry authenticationProviderEntry2 = mock(ConfigurationEntry.class); - _brokerEntryChildren.put(AuthenticationProvider.class.getSimpleName(), Arrays.asList(_authenticationProviderEntry1, authenticationProviderEntry2)); - - //Set the default authentication provider - Map brokerAtttributes = new HashMap(); - when(_brokerEntry.getAttributes()).thenReturn(brokerAtttributes); - brokerAtttributes.put(Broker.DEFAULT_AUTHENTICATION_PROVIDER, "authenticationProvider2"); - - //Create a group provider - ConfigurationEntry groupProviderEntry = mock(ConfigurationEntry.class); - GroupProvider groupProvider = mock(GroupProvider.class); - _brokerEntryChildren.put(GroupProvider.class.getSimpleName(), Arrays.asList(groupProviderEntry)); - - RecovererProvider recovererProvider = createRecoveryProvider( - new ConfigurationEntry[]{groupProviderEntry, authenticationProviderEntry2, _authenticationProviderEntry1}, - new ConfiguredObject[]{groupProvider, authenticationProvider2, _authenticationProvider1}); - - Broker broker = _brokerRecoverer.create(recovererProvider, _brokerEntry); - - assertNotNull(broker); - assertEquals("Unexpected number of authentication providers", 2, broker.getAuthenticationProviders().size()); - } public void testCreateBrokerWithGroupProvider() diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/startup/DefaultRecovererProviderTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/startup/DefaultRecovererProviderTest.java index 96f2474c2d..b958ba1f56 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/startup/DefaultRecovererProviderTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/startup/DefaultRecovererProviderTest.java @@ -23,6 +23,7 @@ package org.apache.qpid.server.configuration.startup; import static org.mockito.Mockito.mock; import junit.framework.TestCase; +import org.apache.qpid.server.BrokerOptions; import org.apache.qpid.server.configuration.ConfiguredObjectRecoverer; import org.apache.qpid.server.logging.LogRecorder; import org.apache.qpid.server.logging.RootMessageLogger; @@ -54,7 +55,7 @@ public class DefaultRecovererProviderTest extends TestCase RootMessageLogger rootMessageLogger = mock(RootMessageLogger.class); TaskExecutor taskExecutor = mock(TaskExecutor.class); - DefaultRecovererProvider provider = new DefaultRecovererProvider(statisticsGatherer, virtualHostRegistry, logRecorder, rootMessageLogger, taskExecutor); + DefaultRecovererProvider provider = new DefaultRecovererProvider(statisticsGatherer, virtualHostRegistry, logRecorder, rootMessageLogger, taskExecutor, mock(BrokerOptions.class)); for (String configuredObjectType : supportedTypes) { ConfiguredObjectRecoverer recovever = provider.getRecoverer(configuredObjectType); diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/store/ConfigurationEntryStoreTestCase.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/store/ConfigurationEntryStoreTestCase.java index 7d253d56f0..fc21706bc0 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/store/ConfigurationEntryStoreTestCase.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/store/ConfigurationEntryStoreTestCase.java @@ -60,7 +60,6 @@ public abstract class ConfigurationEntryStoreTestCase extends QpidTestCase _brokerId = UUID.randomUUID(); _brokerAttributes = new HashMap(); _brokerAttributes.put(Broker.DEFAULT_VIRTUAL_HOST, "test"); - _brokerAttributes.put(Broker.DEFAULT_AUTHENTICATION_PROVIDER, "authenticationProvider1"); _brokerAttributes.put(Broker.QUEUE_ALERT_THRESHOLD_MESSAGE_AGE, 9); _brokerAttributes.put(Broker.QUEUE_ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES, 8); _brokerAttributes.put(Broker.QUEUE_ALERT_THRESHOLD_QUEUE_DEPTH_BYTES, 7); @@ -171,7 +170,6 @@ public abstract class ConfigurationEntryStoreTestCase extends QpidTestCase ConfigurationEntry brokerConfigEntry = _store.getRootEntry(); Map attributes = new HashMap(); attributes.put(Broker.DEFAULT_VIRTUAL_HOST, "test"); - attributes.put(Broker.DEFAULT_AUTHENTICATION_PROVIDER, "authenticationProvider1"); attributes.put(Broker.QUEUE_ALERT_THRESHOLD_MESSAGE_AGE, 19); attributes.put(Broker.QUEUE_ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES, 18); attributes.put(Broker.QUEUE_ALERT_THRESHOLD_QUEUE_DEPTH_BYTES, 17); diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/model/BrokerShutdownTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/model/BrokerShutdownTest.java index 7c1db6348b..eb5c672eb8 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/model/BrokerShutdownTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/model/BrokerShutdownTest.java @@ -23,6 +23,7 @@ package org.apache.qpid.server.model; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import org.apache.qpid.server.BrokerOptions; import org.apache.qpid.server.configuration.ConfigurationEntry; import org.apache.qpid.server.configuration.ConfigurationEntryStore; import org.apache.qpid.server.configuration.ConfiguredObjectRecoverer; @@ -121,7 +122,7 @@ public class BrokerShutdownTest extends QpidTestCase RootMessageLogger rootMessageLogger = mock(RootMessageLogger.class); // recover the broker from the store - RecovererProvider provider = new DefaultRecovererProvider(statisticsGatherer, virtualHostRegistry, logRecorder, rootMessageLogger, _taskExecutor); + RecovererProvider provider = new DefaultRecovererProvider(statisticsGatherer, virtualHostRegistry, logRecorder, rootMessageLogger, _taskExecutor, mock(BrokerOptions.class)); ConfiguredObjectRecoverer brokerRecoverer = provider.getRecoverer(Broker.class.getSimpleName()); Broker broker = (Broker) brokerRecoverer.create(provider, store.getRootEntry()); diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/model/adapter/PortFactoryTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/model/adapter/PortFactoryTest.java index 53fb1a0620..54826b8c88 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/model/adapter/PortFactoryTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/model/adapter/PortFactoryTest.java @@ -36,6 +36,7 @@ import java.util.UUID; import org.apache.qpid.server.configuration.BrokerProperties; import org.apache.qpid.server.configuration.IllegalConfigurationException; +import org.apache.qpid.server.model.AuthenticationProvider; import org.apache.qpid.server.model.Broker; import org.apache.qpid.server.model.KeyStore; import org.apache.qpid.server.model.Port; @@ -58,19 +59,22 @@ public class PortFactoryTest extends QpidTestCase private Broker _broker = mock(Broker.class); private KeyStore _keyStore = mock(KeyStore.class); private TrustStore _trustStore = mock(TrustStore.class); - + private String _authProviderName = "authProvider"; + private AuthenticationProvider _authProvider = mock(AuthenticationProvider.class); private PortFactory _portFactory; @Override protected void setUp() throws Exception { + when(_broker.findAuthenticationProviderByName(_authProviderName)).thenReturn(_authProvider); + setTestSystemProperty(BrokerProperties.PROPERTY_BROKER_DEFAULT_AMQP_PROTOCOL_EXCLUDES, null); setTestSystemProperty(BrokerProperties.PROPERTY_BROKER_DEFAULT_AMQP_PROTOCOL_INCLUDES, null); _portFactory = new PortFactory(); _attributes.put(Port.PORT, _portNumber); _attributes.put(Port.TRANSPORTS, _tcpStringSet); - + _attributes.put(Port.AUTHENTICATION_PROVIDER, _authProviderName); _attributes.put(Port.TCP_NO_DELAY, "true"); _attributes.put(Port.RECEIVE_BUFFER_SIZE, "1"); _attributes.put(Port.SEND_BUFFER_SIZE, "2"); @@ -111,6 +115,7 @@ public class PortFactoryTest extends QpidTestCase { Map attributes = new HashMap(); attributes.put(Port.PORT, 1); + attributes.put(Port.AUTHENTICATION_PROVIDER, _authProviderName); Port port = _portFactory.createPort(_portId, _broker, attributes); assertNotNull(port); @@ -273,6 +278,7 @@ public class PortFactoryTest extends QpidTestCase Set nonAmqpStringSet = Collections.singleton(Protocol.JMX_RMI.name()); _attributes = new HashMap(); _attributes.put(Port.PROTOCOLS, nonAmqpStringSet); + _attributes.put(Port.AUTHENTICATION_PROVIDER, _authProviderName); _attributes.put(Port.PORT, _portNumber); _attributes.put(Port.TRANSPORTS, _tcpStringSet); @@ -298,6 +304,7 @@ public class PortFactoryTest extends QpidTestCase Set nonAmqpStringSet = Collections.singleton(Protocol.JMX_RMI.name()); _attributes = new HashMap(); _attributes.put(Port.PROTOCOLS, nonAmqpStringSet); + _attributes.put(Port.AUTHENTICATION_PROVIDER, _authProviderName); _attributes.put(Port.PORT, _portNumber); Port port = _portFactory.createPort(_portId, _broker, _attributes); diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java deleted file mode 100644 index c41b9bf081..0000000000 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * 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.database; - -import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; -import org.apache.qpid.server.security.auth.UsernamePrincipal; -import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5Initialiser; -import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser; - -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.login.AccountNotFoundException; - -import java.io.File; -import java.io.IOException; -import java.security.Principal; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Properties; - -public class PropertiesPrincipalDatabase implements PrincipalDatabase -{ - private Properties _users; - - private Map _saslServers; - - public PropertiesPrincipalDatabase(Properties users) - { - _users = users; - - _saslServers = new HashMap(); - - /** - * Create Authenticators for Properties Principal Database. - */ - - // Accept MD5 incomming and use plain comparison with the file - PlainInitialiser cram = new PlainInitialiser(); - cram.initialise(this); - // Accept Plain incomming and hash it for comparison to the file. - CRAMMD5Initialiser plain = new CRAMMD5Initialiser(); - plain.initialise(this, CRAMMD5Initialiser.HashDirection.INCOMMING); - - _saslServers.put(plain.getMechanismName(), cram); - _saslServers.put(cram.getMechanismName(), plain); - } - - public void setPassword(Principal principal, PasswordCallback callback) throws IOException, AccountNotFoundException - { - if (principal == null) - { - throw new IllegalArgumentException("principal must not be null"); - } - - - - final String pwd = _users.getProperty(principal.getName()); - - if (pwd != null) - { - callback.setPassword(pwd.toCharArray()); - } - else - { - throw new AccountNotFoundException("No account found for principal " + principal); - } - } - - public boolean verifyPassword(String principal, char[] password) throws AccountNotFoundException - { - //fixme this is not correct as toCharArray is not safe based on the type of string. - char[] pwd = _users.getProperty(principal).toCharArray(); - - return compareCharArray(pwd, password); - } - - public boolean updatePassword(Principal principal, char[] password) throws AccountNotFoundException - { - return false; // updates denied - } - - public boolean createPrincipal(Principal principal, char[] password) - { - return false; // updates denied - } - - public boolean deletePrincipal(Principal principal) throws AccountNotFoundException - { - return false; // updates denied - } - - private boolean compareCharArray(char[] a, char[] b) - { - boolean equal = false; - if (a.length == b.length) - { - equal = true; - int index = 0; - while (equal && index < a.length) - { - equal = a[index] == b[index]; - index++; - } - } - return equal; - } - - - public Map getMechanisms() - { - return _saslServers; - } - - public List getUsers() - { - return new LinkedList(); //todo - } - - public Principal getUser(String username) - { - if (_users.getProperty(username) != null) - { - return new UsernamePrincipal(username); - } - else - { - return null; - } - } - - public void reload() throws IOException - { - //No file to update from, so do nothing. - } - - @Override - public void open(File passwordFile) - { - throw new UnsupportedOperationException(); - } -} diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/jmx/JMXPasswordAuthenticatorTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/jmx/JMXPasswordAuthenticatorTest.java new file mode 100644 index 0000000000..a4dd97e6a1 --- /dev/null +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/jmx/JMXPasswordAuthenticatorTest.java @@ -0,0 +1,259 @@ +/* + * + * 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.jmx; + +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.security.Principal; +import java.util.regex.Pattern; + +import javax.security.auth.Subject; + +import junit.framework.TestCase; + +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.security.SubjectCreator; +import org.apache.qpid.server.security.auth.AuthenticationResult; +import org.apache.qpid.server.security.auth.AuthenticationResult.AuthenticationStatus; +import org.apache.qpid.server.security.auth.jmx.JMXPasswordAuthenticator; +import org.apache.qpid.server.security.auth.SubjectAuthenticationResult; +import org.apache.qpid.server.security.SecurityManager; + +/** + * Tests the JMXPasswordAuthenticator and its collaboration with the AuthenticationManager. + * + */ +public class JMXPasswordAuthenticatorTest extends TestCase +{ + private static final String USERNAME = "guest"; + private static final String PASSWORD = "password"; + + private final Broker _broker = mock(Broker.class); + private final SecurityManager _securityManager = mock(SecurityManager.class); + private final Subject _loginSubject = new Subject(); + private final String[] _credentials = new String[] {USERNAME, PASSWORD}; + + private JMXPasswordAuthenticator _rmipa; + + private SubjectCreator _usernamePasswordOkaySuvjectCreator = createMockSubjectCreator(true, null); + private SubjectCreator _badPasswordSubjectCreator = createMockSubjectCreator(false, null); + + protected void setUp() throws Exception + { + when(_broker.getSecurityManager()).thenReturn(_securityManager); + _rmipa = new JMXPasswordAuthenticator(_broker, new InetSocketAddress(8999)); + } + + /** + * Tests a successful authentication. Ensures that the expected subject is returned. + */ + public void testAuthenticationSuccess() + { + when(_broker.getSubjectCreator(any(SocketAddress.class))).thenReturn(_usernamePasswordOkaySuvjectCreator); + when(_securityManager.accessManagement()).thenReturn(true); + + Subject newSubject = _rmipa.authenticate(_credentials); + assertSame("Subject must be unchanged", _loginSubject, newSubject); + } + + /** + * Tests a unsuccessful authentication. + */ + public void testUsernameOrPasswordInvalid() + { + when(_broker.getSubjectCreator(any(SocketAddress.class))).thenReturn(_badPasswordSubjectCreator); + + try + { + _rmipa.authenticate(_credentials); + fail("Exception not thrown"); + } + catch (SecurityException se) + { + assertEquals("Unexpected exception message", + JMXPasswordAuthenticator.INVALID_CREDENTIALS, se.getMessage()); + } + } + + public void testAuthorisationFailure() + { + when(_broker.getSubjectCreator(any(SocketAddress.class))).thenReturn(_usernamePasswordOkaySuvjectCreator); + when(_securityManager.accessManagement()).thenReturn(false); + + try + { + _rmipa.authenticate(_credentials); + fail("Exception not thrown"); + } + catch (SecurityException se) + { + assertEquals("Unexpected exception message", + JMXPasswordAuthenticator.USER_NOT_AUTHORISED_FOR_MANAGEMENT, se.getMessage()); + } + } + + public void testSubjectCreatorInternalFailure() + { + final Exception mockAuthException = new Exception("Mock Auth system failure"); + SubjectCreator subjectCreator = createMockSubjectCreator(false, mockAuthException); + when(_broker.getSubjectCreator(any(SocketAddress.class))).thenReturn(subjectCreator); + + try + { + _rmipa.authenticate(_credentials); + fail("Exception not thrown"); + } + catch (SecurityException se) + { + assertEquals("Initial cause not found", mockAuthException, se.getCause()); + } + } + + /** + * Tests case where authentication manager is not set. + */ + public void testNullSubjectCreator() throws Exception + { + when(_broker.getSubjectCreator(any(SocketAddress.class))).thenReturn(null); + + try + { + _rmipa.authenticate(_credentials); + fail("SecurityException expected due to lack of authentication manager"); + } + catch (SecurityException se) + { + assertTrue("Unexpected exception message", Pattern.matches("Can't get subject creator for .*:8999", se.getMessage())); + } + } + + /** + * Tests case where arguments are non-Strings.. + */ + public void testWithNonStringArrayArgument() + { + // Test handling of non-string credential's + final Object[] objCredentials = new Object[]{USERNAME, PASSWORD}; + try + { + _rmipa.authenticate(objCredentials); + fail("SecurityException expected due to non string[] credentials"); + } + catch (SecurityException se) + { + assertEquals("Unexpected exception message", + JMXPasswordAuthenticator.SHOULD_BE_STRING_ARRAY, se.getMessage()); + } + } + + /** + * Tests case where there are too many, too few or null arguments. + */ + public void testWithIllegalNumberOfArguments() + { + String[] credentials; + + // Test handling of incorrect number of credentials + try + { + credentials = new String[]{USERNAME, PASSWORD, PASSWORD}; + _rmipa.authenticate(credentials); + fail("SecurityException expected due to supplying wrong number of credentials"); + } + catch (SecurityException se) + { + assertEquals("Unexpected exception message", + JMXPasswordAuthenticator.SHOULD_HAVE_2_ELEMENTS, se.getMessage()); + } + + // Test handling of null credentials + try + { + //send a null array + credentials = null; + _rmipa.authenticate(credentials); + fail("SecurityException expected due to not supplying an array of credentials"); + } + catch (SecurityException se) + { + assertEquals("Unexpected exception message", + JMXPasswordAuthenticator.CREDENTIALS_REQUIRED, se.getMessage()); + } + + try + { + //send a null password + credentials = new String[]{USERNAME, null}; + _rmipa.authenticate(credentials); + fail("SecurityException expected due to sending a null password"); + } + catch (SecurityException se) + { + assertEquals("Unexpected exception message", + JMXPasswordAuthenticator.SHOULD_BE_NON_NULL, se.getMessage()); + } + + try + { + //send a null username + credentials = new String[]{null, PASSWORD}; + _rmipa.authenticate(credentials); + fail("SecurityException expected due to sending a null username"); + } + catch (SecurityException se) + { + assertEquals("Unexpected exception message", + JMXPasswordAuthenticator.SHOULD_BE_NON_NULL, se.getMessage()); + } + } + + private SubjectCreator createMockSubjectCreator(final boolean successfulAuth, final Exception exception) + { + SubjectCreator subjectCreator = mock(SubjectCreator.class); + + SubjectAuthenticationResult subjectAuthenticationResult; + + if (exception != null) { + + subjectAuthenticationResult = new SubjectAuthenticationResult( + new AuthenticationResult(AuthenticationStatus.ERROR, exception)); + } + else if (successfulAuth) + { + + subjectAuthenticationResult = new SubjectAuthenticationResult( + new AuthenticationResult(mock(Principal.class)), _loginSubject); + } + else + { + subjectAuthenticationResult = new SubjectAuthenticationResult(new AuthenticationResult(AuthenticationStatus.CONTINUE)); + } + + when(subjectCreator.authenticate(anyString(), anyString())).thenReturn(subjectAuthenticationResult); + + return subjectCreator; + } +} diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/SimpleAuthenticationManagerTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/SimpleAuthenticationManagerTest.java new file mode 100644 index 0000000000..5868f44b8f --- /dev/null +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/SimpleAuthenticationManagerTest.java @@ -0,0 +1,140 @@ +package org.apache.qpid.server.security.auth.manager; + +import java.security.Principal; +import java.util.Set; + +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +import org.apache.qpid.server.security.auth.AuthenticationResult; +import org.apache.qpid.server.security.auth.AuthenticationResult.AuthenticationStatus; +import org.apache.qpid.server.security.auth.sasl.SaslUtil; +import org.apache.qpid.server.security.auth.sasl.plain.PlainSaslServer; +import org.apache.qpid.test.utils.QpidTestCase; + +public class SimpleAuthenticationManagerTest extends QpidTestCase +{ + private static final String TEST_USER = "testUser"; + private static final String TEST_PASSWORD = "testPassword"; + private AuthenticationManager _authenticationManager; + + public void setUp() throws Exception + { + super.setUp(); + _authenticationManager = new SimpleAuthenticationManager(TEST_USER, TEST_PASSWORD); + } + + public void testGetMechanisms() + { + assertEquals("Unexpected mechanisms", "PLAIN CRAM-MD5", _authenticationManager.getMechanisms()); + } + + public void testCreateSaslServerForUnsupportedMechanisms() throws Exception + { + String[] unsupported = new String[] { "EXTERNAL", "CRAM-MD5-HEX", "CRAM-MD5-HASHED", "ANONYMOUS", "GSSAPI"}; + for (int i = 0; i < unsupported.length; i++) + { + String mechanism = unsupported[i]; + try + { + _authenticationManager.createSaslServer(mechanism, "test", null); + fail("Mechanism " + mechanism + " should not be supported by SimpleAuthenticationManager"); + } + catch (SaslException e) + { + // pass + } + } + } + + public void testAuthenticateWithPlainSaslServer() throws Exception + { + AuthenticationResult result = authenticatePlain(TEST_USER, TEST_PASSWORD); + assertAuthenticated(result); + } + + public void testAuthenticateWithPlainSaslServerInvalidPassword() throws Exception + { + AuthenticationResult result = authenticatePlain(TEST_USER, "wrong-password"); + assertUnauthenticated(result); + } + + public void testAuthenticateWithPlainSaslServerInvalidUsername() throws Exception + { + AuthenticationResult result = authenticatePlain("wrong-user", TEST_PASSWORD); + assertUnauthenticated(result); + } + + public void testAuthenticateWithCramMd5SaslServer() throws Exception + { + AuthenticationResult result = authenticateCramMd5(TEST_USER, TEST_PASSWORD); + assertAuthenticated(result); + } + + public void testAuthenticateWithCramMd5SaslServerInvalidPassword() throws Exception + { + AuthenticationResult result = authenticateCramMd5(TEST_USER, "wrong-password"); + assertUnauthenticated(result); + } + + public void testAuthenticateWithCramMd5SaslServerInvalidUsername() throws Exception + { + AuthenticationResult result = authenticateCramMd5("wrong-user", TEST_PASSWORD); + assertUnauthenticated(result); + } + + public void testAuthenticateValidCredentials() + { + AuthenticationResult result = _authenticationManager.authenticate(TEST_USER, TEST_PASSWORD); + assertEquals("Unexpected authentication result", AuthenticationStatus.SUCCESS, result.getStatus()); + assertAuthenticated(result); + } + + public void testAuthenticateInvalidPassword() + { + AuthenticationResult result = _authenticationManager.authenticate(TEST_USER, "invalid"); + assertUnauthenticated(result); + } + + public void testAuthenticateInvalidUserName() + { + AuthenticationResult result = _authenticationManager.authenticate("invalid", TEST_PASSWORD); + assertUnauthenticated(result); + } + + private void assertAuthenticated(AuthenticationResult result) + { + assertEquals("Unexpected authentication result", AuthenticationStatus.SUCCESS, result.getStatus()); + Principal principal = result.getMainPrincipal(); + assertEquals("Unexpected principal name", TEST_USER, principal.getName()); + Set principals = result.getPrincipals(); + assertEquals("Unexpected principals size", 1, principals.size()); + assertEquals("Unexpected principal name", TEST_USER, principals.iterator().next().getName()); + } + + private void assertUnauthenticated(AuthenticationResult result) + { + assertEquals("Unexpected authentication result", AuthenticationStatus.ERROR, result.getStatus()); + assertNull("Unexpected principal", result.getMainPrincipal()); + Set principals = result.getPrincipals(); + assertEquals("Unexpected principals size", 0, principals.size()); + } + + private AuthenticationResult authenticatePlain(String userName, String userPassword) throws SaslException, Exception + { + PlainSaslServer ss = (PlainSaslServer) _authenticationManager.createSaslServer("PLAIN", "test", null); + byte[] response = SaslUtil.generatePlainClientResponse(userName, userPassword); + + return _authenticationManager.authenticate(ss, response); + } + + private AuthenticationResult authenticateCramMd5(String userName, String userPassword) throws SaslException, Exception + { + SaslServer ss = _authenticationManager.createSaslServer("CRAM-MD5", "test", null); + byte[] challenge = ss.evaluateResponse(new byte[0]); + byte[] response = SaslUtil.generateCramMD5ClientResponse(userName, userPassword, challenge); + + AuthenticationResult result = _authenticationManager.authenticate(ss, response); + return result; + } +} 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 deleted file mode 100644 index 52b525dd80..0000000000 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticatorTest.java +++ /dev/null @@ -1,258 +0,0 @@ -/* - * - * 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.rmi; - -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.security.Principal; -import java.util.regex.Pattern; - -import javax.security.auth.Subject; - -import junit.framework.TestCase; - -import org.apache.qpid.server.model.Broker; -import org.apache.qpid.server.security.SubjectCreator; -import org.apache.qpid.server.security.auth.AuthenticationResult; -import org.apache.qpid.server.security.auth.AuthenticationResult.AuthenticationStatus; -import org.apache.qpid.server.security.auth.SubjectAuthenticationResult; -import org.apache.qpid.server.security.SecurityManager; - -/** - * Tests the RMIPasswordAuthenticator and its collaboration with the AuthenticationManager. - * - */ -public class RMIPasswordAuthenticatorTest extends TestCase -{ - private static final String USERNAME = "guest"; - private static final String PASSWORD = "password"; - - private final Broker _broker = mock(Broker.class); - private final SecurityManager _securityManager = mock(SecurityManager.class); - private final Subject _loginSubject = new Subject(); - private final String[] _credentials = new String[] {USERNAME, PASSWORD}; - - private RMIPasswordAuthenticator _rmipa; - - private SubjectCreator _usernamePasswordOkaySuvjectCreator = createMockSubjectCreator(true, null); - private SubjectCreator _badPasswordSubjectCreator = createMockSubjectCreator(false, null); - - protected void setUp() throws Exception - { - when(_broker.getSecurityManager()).thenReturn(_securityManager); - _rmipa = new RMIPasswordAuthenticator(_broker, new InetSocketAddress(8999)); - } - - /** - * Tests a successful authentication. Ensures that the expected subject is returned. - */ - public void testAuthenticationSuccess() - { - when(_broker.getSubjectCreator(any(SocketAddress.class))).thenReturn(_usernamePasswordOkaySuvjectCreator); - when(_securityManager.accessManagement()).thenReturn(true); - - Subject newSubject = _rmipa.authenticate(_credentials); - assertSame("Subject must be unchanged", _loginSubject, newSubject); - } - - /** - * Tests a unsuccessful authentication. - */ - public void testUsernameOrPasswordInvalid() - { - when(_broker.getSubjectCreator(any(SocketAddress.class))).thenReturn(_badPasswordSubjectCreator); - - try - { - _rmipa.authenticate(_credentials); - fail("Exception not thrown"); - } - catch (SecurityException se) - { - assertEquals("Unexpected exception message", - RMIPasswordAuthenticator.INVALID_CREDENTIALS, se.getMessage()); - } - } - - public void testAuthorisationFailure() - { - when(_broker.getSubjectCreator(any(SocketAddress.class))).thenReturn(_usernamePasswordOkaySuvjectCreator); - when(_securityManager.accessManagement()).thenReturn(false); - - try - { - _rmipa.authenticate(_credentials); - fail("Exception not thrown"); - } - catch (SecurityException se) - { - assertEquals("Unexpected exception message", - RMIPasswordAuthenticator.USER_NOT_AUTHORISED_FOR_MANAGEMENT, se.getMessage()); - } - } - - public void testSubjectCreatorInternalFailure() - { - final Exception mockAuthException = new Exception("Mock Auth system failure"); - SubjectCreator subjectCreator = createMockSubjectCreator(false, mockAuthException); - when(_broker.getSubjectCreator(any(SocketAddress.class))).thenReturn(subjectCreator); - - try - { - _rmipa.authenticate(_credentials); - fail("Exception not thrown"); - } - catch (SecurityException se) - { - assertEquals("Initial cause not found", mockAuthException, se.getCause()); - } - } - - /** - * Tests case where authentication manager is not set. - */ - public void testNullSubjectCreator() throws Exception - { - when(_broker.getSubjectCreator(any(SocketAddress.class))).thenReturn(null); - - try - { - _rmipa.authenticate(_credentials); - fail("SecurityException expected due to lack of authentication manager"); - } - catch (SecurityException se) - { - assertTrue("Unexpected exception message", Pattern.matches("Can't get subject creator for .*:8999", se.getMessage())); - } - } - - /** - * Tests case where arguments are non-Strings.. - */ - public void testWithNonStringArrayArgument() - { - // Test handling of non-string credential's - final Object[] objCredentials = new Object[]{USERNAME, PASSWORD}; - try - { - _rmipa.authenticate(objCredentials); - fail("SecurityException expected due to non string[] credentials"); - } - catch (SecurityException se) - { - assertEquals("Unexpected exception message", - RMIPasswordAuthenticator.SHOULD_BE_STRING_ARRAY, se.getMessage()); - } - } - - /** - * Tests case where there are too many, too few or null arguments. - */ - public void testWithIllegalNumberOfArguments() - { - String[] credentials; - - // Test handling of incorrect number of credentials - try - { - credentials = new String[]{USERNAME, PASSWORD, PASSWORD}; - _rmipa.authenticate(credentials); - fail("SecurityException expected due to supplying wrong number of credentials"); - } - catch (SecurityException se) - { - assertEquals("Unexpected exception message", - RMIPasswordAuthenticator.SHOULD_HAVE_2_ELEMENTS, se.getMessage()); - } - - // Test handling of null credentials - try - { - //send a null array - credentials = null; - _rmipa.authenticate(credentials); - fail("SecurityException expected due to not supplying an array of credentials"); - } - catch (SecurityException se) - { - assertEquals("Unexpected exception message", - RMIPasswordAuthenticator.CREDENTIALS_REQUIRED, se.getMessage()); - } - - try - { - //send a null password - credentials = new String[]{USERNAME, null}; - _rmipa.authenticate(credentials); - fail("SecurityException expected due to sending a null password"); - } - catch (SecurityException se) - { - assertEquals("Unexpected exception message", - RMIPasswordAuthenticator.SHOULD_BE_NON_NULL, se.getMessage()); - } - - try - { - //send a null username - credentials = new String[]{null, PASSWORD}; - _rmipa.authenticate(credentials); - fail("SecurityException expected due to sending a null username"); - } - catch (SecurityException se) - { - assertEquals("Unexpected exception message", - RMIPasswordAuthenticator.SHOULD_BE_NON_NULL, se.getMessage()); - } - } - - private SubjectCreator createMockSubjectCreator(final boolean successfulAuth, final Exception exception) - { - SubjectCreator subjectCreator = mock(SubjectCreator.class); - - SubjectAuthenticationResult subjectAuthenticationResult; - - if (exception != null) { - - subjectAuthenticationResult = new SubjectAuthenticationResult( - new AuthenticationResult(AuthenticationStatus.ERROR, exception)); - } - else if (successfulAuth) - { - - subjectAuthenticationResult = new SubjectAuthenticationResult( - new AuthenticationResult(mock(Principal.class)), _loginSubject); - } - else - { - subjectAuthenticationResult = new SubjectAuthenticationResult(new AuthenticationResult(AuthenticationStatus.CONTINUE)); - } - - when(subjectCreator.authenticate(anyString(), anyString())).thenReturn(subjectAuthenticationResult); - - return subjectCreator; - } -} diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/CRAMMD5HexInitialiserTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/CRAMMD5HexInitialiserTest.java index e408fd73d5..3079222b1c 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/CRAMMD5HexInitialiserTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/CRAMMD5HexInitialiserTest.java @@ -20,88 +20,94 @@ */ package org.apache.qpid.server.security.auth.sasl; -import junit.framework.TestCase; - -import org.apache.qpid.server.security.auth.database.PropertiesPrincipalDatabase; -import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HexInitialiser; +import java.io.File; +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import javax.security.auth.callback.Callback; import javax.security.auth.callback.NameCallback; import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.callback.UnsupportedCallbackException; -import java.io.IOException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Properties; + +import junit.framework.TestCase; + +import org.apache.qpid.server.security.auth.database.Base64MD5PasswordFilePrincipalDatabase; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HexInitialiser; +import org.apache.qpid.test.utils.TestFileUtils; +import org.apache.qpid.tools.security.Passwd; /** * These tests ensure that the Hex wrapping that the initialiser performs does actually operate when the handle method is called. */ public class CRAMMD5HexInitialiserTest extends TestCase { - public void testHex() - { - //Create User details for testing - String user = "testUser"; - String password = "testPassword"; + private static final String TEST_PASSWORD = "testPassword"; + private static final String TEST_USER = "testUser"; + private File _file; - perform(user, password); - } - - public void testHashedHex() + public void testHashedHex() throws Exception { - //Create User details for testing - String user = "testUser"; - String password = "testPassword"; - - //Create a hashed password that we then attempt to put through the call back mechanism. - try - { - password = new String(MessageDigest.getInstance("MD5").digest(password.getBytes())); - } - catch (NoSuchAlgorithmException e) - { - fail(e.getMessage()); - } - - perform(user, password); + perform(TEST_USER, getHash(TEST_PASSWORD)); } - public void perform(String user, String password) + public void perform(String user, char[] password) throws Exception { CRAMMD5HexInitialiser initialiser = new CRAMMD5HexInitialiser(); - //Use properties to create a PrincipalDatabase - Properties users = new Properties(); - users.put(user, password); - - PropertiesPrincipalDatabase db = new PropertiesPrincipalDatabase(users); - + PrincipalDatabase db = new Base64MD5PasswordFilePrincipalDatabase(); + db.open(_file); initialiser.initialise(db); - //setup the callbacks PasswordCallback passwordCallback = new PasswordCallback("password:", false); NameCallback usernameCallback = new NameCallback("user:", user); Callback[] callbacks = new Callback[]{usernameCallback, passwordCallback}; - //Check the - try + assertNull("The password was not null before the handle call.", passwordCallback.getPassword()); + initialiser.getCallbackHandler().handle(callbacks); + + assertArrayEquals(toHex(password), passwordCallback.getPassword()); + } + + public void setUp() throws Exception + { + super.setUp(); + _file = TestFileUtils.createTempFile(this, "password-file", new Passwd().getOutput(TEST_USER , TEST_PASSWORD)); + } + + public void tearDown() throws Exception + { + if (_file != null) { - assertNull("The password was not null before the handle call.", passwordCallback.getPassword()); - initialiser.getCallbackHandler().handle(callbacks); + _file.delete(); } - catch (IOException e) + super.tearDown(); + } + + private char[] getHash(String text) throws NoSuchAlgorithmException, UnsupportedEncodingException + { + + byte[] data = text.getBytes("utf-8"); + + MessageDigest md = MessageDigest.getInstance("MD5"); + + for (byte b : data) { - fail(e.getMessage()); + md.update(b); } - catch (UnsupportedCallbackException e) + + byte[] digest = md.digest(); + + char[] hash = new char[digest.length]; + + int index = 0; + for (byte b : digest) { - fail(e.getMessage()); + hash[index++] = (char) b; } - //Hex the password we initialised with and compare it with the passwordCallback - assertArrayEquals(toHex(password.toCharArray()), passwordCallback.getPassword()); + return hash; } private void assertArrayEquals(char[] expected, char[] actual) @@ -135,4 +141,5 @@ public class CRAMMD5HexInitialiserTest extends TestCase return hex; } + } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/SaslUtil.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/SaslUtil.java new file mode 100644 index 0000000000..251ebc4c81 --- /dev/null +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/SaslUtil.java @@ -0,0 +1,85 @@ +/* + * + * 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.sasl; + +import java.security.MessageDigest; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + +public class SaslUtil +{ + + private static byte SEPARATOR = 0; + + public static byte[] generatePlainClientResponse(String userName, String userPassword) throws Exception + { + byte[] password = userPassword.getBytes("UTF8"); + byte user[] = userName.getBytes("UTF8"); + byte response[] = new byte[password.length + user.length + 2]; + int size = 0; + response[size++] = SEPARATOR; + System.arraycopy(user, 0, response, size, user.length); + size += user.length; + response[size++] = SEPARATOR; + System.arraycopy(password, 0, response, size, password.length); + return response; + } + + public static byte[] generateCramMD5HexClientResponse(String userName, String userPassword, byte[] challengeBytes) + throws Exception + { + String macAlgorithm = "HmacMD5"; + byte[] digestedPasswordBytes = MessageDigest.getInstance("MD5").digest(userPassword.getBytes("UTF-8")); + byte[] hexEncodedDigestedPasswordBytes = toHex(digestedPasswordBytes).getBytes("UTF-8"); + Mac mac = Mac.getInstance(macAlgorithm); + mac.init(new SecretKeySpec(hexEncodedDigestedPasswordBytes, macAlgorithm)); + final byte[] messageAuthenticationCode = mac.doFinal(challengeBytes); + String responseAsString = userName + " " + toHex(messageAuthenticationCode); + return responseAsString.getBytes(); + } + + public static byte[] generateCramMD5ClientResponse(String userName, String userPassword, byte[] challengeBytes) + throws Exception + { + String macAlgorithm = "HmacMD5"; + Mac mac = Mac.getInstance(macAlgorithm); + mac.init(new SecretKeySpec(userPassword.getBytes("UTF-8"), macAlgorithm)); + final byte[] messageAuthenticationCode = mac.doFinal(challengeBytes); + String responseAsString = userName + " " + toHex(messageAuthenticationCode); + return responseAsString.getBytes(); + } + + public static String toHex(byte[] data) + { + StringBuffer hash = new StringBuffer(); + for (int i = 0; i < data.length; i++) + { + String hex = Integer.toHexString(0xFF & data[i]); + if (hex.length() == 1) + { + hash.append('0'); + } + hash.append(hex); + } + return hash.toString(); + } +} diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/util/StringUtilTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/util/StringUtilTest.java new file mode 100644 index 0000000000..93b4172792 --- /dev/null +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/util/StringUtilTest.java @@ -0,0 +1,38 @@ +package org.apache.qpid.server.util; + +import org.apache.qpid.server.util.StringUtil; +import org.apache.qpid.test.utils.QpidTestCase; + +public class StringUtilTest extends QpidTestCase +{ + private StringUtil _util; + + @Override + public void setUp() throws Exception + { + super.setUp(); + _util = new StringUtil(); + } + + public void testRandomAlphaNumericStringInt() + { + String password = _util.randomAlphaNumericString(10); + assertEquals("Unexpected password string length", 10, password.length()); + assertCharacters(password); + } + + private void assertCharacters(String password) + { + String numbers = "0123456789"; + String letters = "abcdefghijklmnopqrstuvwxwy"; + String others = "_-"; + String expectedCharacters = (numbers + letters + letters.toUpperCase() + others); + char[] chars = password.toCharArray(); + for (int i = 0; i < chars.length; i++) + { + char ch = chars[i]; + assertTrue("Unexpected character " + ch, expectedCharacters.indexOf(ch) != -1); + } + } + +} -- cgit v1.2.1