summaryrefslogtreecommitdiff
path: root/qpid/java
diff options
context:
space:
mode:
authorRobert Godfrey <rgodfrey@apache.org>2014-10-17 13:51:10 +0000
committerRobert Godfrey <rgodfrey@apache.org>2014-10-17 13:51:10 +0000
commit152b079dacea71ccd5efe7ef0458836d8aea8d2f (patch)
treecf0c33645ac33415488c710adeaf0a53454ae4d1 /qpid/java
parentba126ca5218e76bd38be239aed9200cb33c66c99 (diff)
downloadqpid-python-152b079dacea71ccd5efe7ef0458836d8aea8d2f.tar.gz
QPID-6162 : Add authentication providers which store user data in the config file
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1632576 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'qpid/java')
-rw-r--r--qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AuthenticationProvider.java4
-rw-r--r--qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/SubjectCreator.java4
-rw-r--r--qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractAuthenticationManager.java14
-rw-r--r--qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractScramAuthenticationManager.java210
-rw-r--r--qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ConfigModelPasswordManagingAuthenticationProvider.java229
-rw-r--r--qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/MD5AuthenticationProvider.java227
-rw-r--r--qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ManagedUser.java (renamed from qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ScramAuthUser.java)48
-rw-r--r--qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/PlainAuthenticationProvider.java176
-rw-r--r--qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/BrokerStoreUpgraderAndRecoverer.java7
-rw-r--r--qpid/java/broker-core/src/main/java/org/apache/qpid/tools/security/Passwd.java70
-rw-r--r--qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/SubjectCreatorTest.java8
-rw-r--r--qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/MD5AuthenticationManagerTest.java (renamed from qpid/java/broker-core/src/test/java/org/apache/qpid/tools/security/PasswdTest.java)37
-rw-r--r--qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/ManagedAuthenticationManagerTestBase.java252
-rw-r--r--qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/PlainAuthenticationManagerTest.java51
-rw-r--r--qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/ScramSHA1AuthenticationManagerTest.java194
-rw-r--r--qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/sasl/CRAMMD5HexInitialiserTest.java10
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js3
-rwxr-xr-xqpid/java/broker/bin/qpid-passwd35
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/scripts/QpidPasswdTest.java80
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementTest.java42
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementWithBase64MD5PasswordsTest.java31
-rw-r--r--qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/SaslRestTest.java11
22 files changed, 1085 insertions, 658 deletions
diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AuthenticationProvider.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AuthenticationProvider.java
index 021431b756..99ffa38173 100644
--- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AuthenticationProvider.java
+++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AuthenticationProvider.java
@@ -48,13 +48,13 @@ public interface AuthenticationProvider<X extends AuthenticationProvider<X>> ext
* Returns the preferences provider associated with this authentication provider
* @return PreferencesProvider
*/
- PreferencesProvider getPreferencesProvider();
+ PreferencesProvider<?> getPreferencesProvider();
/**
* Sets the preferences provider
* @param preferencesProvider
*/
- void setPreferencesProvider(PreferencesProvider preferencesProvider);
+ void setPreferencesProvider(PreferencesProvider<?> preferencesProvider);
void recoverUser(User user);
diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/SubjectCreator.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/SubjectCreator.java
index ac8d002577..bbec239d74 100644
--- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/SubjectCreator.java
+++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/SubjectCreator.java
@@ -53,10 +53,10 @@ public class SubjectCreator
{
private final boolean _secure;
private AuthenticationProvider<?> _authenticationProvider;
- private Collection<GroupProvider> _groupProviders;
+ private Collection<GroupProvider<?>> _groupProviders;
public SubjectCreator(AuthenticationProvider<?> authenticationProvider,
- Collection<GroupProvider> groupProviders,
+ Collection<GroupProvider<?>> groupProviders,
final boolean secure)
{
_authenticationProvider = authenticationProvider;
diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractAuthenticationManager.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractAuthenticationManager.java
index b2cf1739ab..7f98468726 100644
--- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractAuthenticationManager.java
+++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractAuthenticationManager.java
@@ -53,13 +53,13 @@ public abstract class AbstractAuthenticationManager<T extends AbstractAuthentica
{
private static final Logger LOGGER = Logger.getLogger(AbstractAuthenticationManager.class);
- private final Broker _broker;
- private PreferencesProvider _preferencesProvider;
+ private final Broker<?> _broker;
+ private PreferencesProvider<?> _preferencesProvider;
@ManagedAttributeField
private List<String> _secureOnlyMechanisms;
- protected AbstractAuthenticationManager(final Map<String, Object> attributes, final Broker broker)
+ protected AbstractAuthenticationManager(final Map<String, Object> attributes, final Broker<?> broker)
{
super(parentsMap(broker), attributes);
_broker = broker;
@@ -120,13 +120,13 @@ public abstract class AbstractAuthenticationManager<T extends AbstractAuthentica
}
@Override
- public PreferencesProvider getPreferencesProvider()
+ public PreferencesProvider<?> getPreferencesProvider()
{
return _preferencesProvider;
}
@Override
- public void setPreferencesProvider(final PreferencesProvider preferencesProvider)
+ public void setPreferencesProvider(final PreferencesProvider<?> preferencesProvider)
{
_preferencesProvider = preferencesProvider;
}
@@ -143,8 +143,8 @@ public abstract class AbstractAuthenticationManager<T extends AbstractAuthentica
{
if(childClass == PreferencesProvider.class)
{
- attributes = new HashMap<String, Object>(attributes);
- PreferencesProvider pp = getObjectFactory().create(PreferencesProvider.class, attributes, this);
+ attributes = new HashMap<>(attributes);
+ PreferencesProvider<?> pp = getObjectFactory().create(PreferencesProvider.class, attributes, this);
_preferencesProvider = pp;
return (C)pp;
diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractScramAuthenticationManager.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractScramAuthenticationManager.java
index 152a9086ec..6887cb99d4 100644
--- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractScramAuthenticationManager.java
+++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractScramAuthenticationManager.java
@@ -20,52 +20,38 @@
*/
package org.apache.qpid.server.security.auth.manager;
-import java.io.IOException;
-import java.nio.charset.Charset;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Collections;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.UUID;
-import java.util.concurrent.ConcurrentHashMap;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
-import javax.security.auth.login.AccountNotFoundException;
import javax.security.sasl.SaslException;
import javax.security.sasl.SaslServer;
import javax.xml.bind.DatatypeConverter;
-import org.apache.qpid.server.configuration.updater.Task;
-import org.apache.qpid.server.configuration.updater.VoidTaskWithException;
import org.apache.qpid.server.model.Broker;
-import org.apache.qpid.server.model.ConfiguredObject;
import org.apache.qpid.server.model.PasswordCredentialManagingAuthenticationProvider;
-import org.apache.qpid.server.model.User;
-import org.apache.qpid.server.security.access.Operation;
import org.apache.qpid.server.security.auth.AuthenticationResult;
import org.apache.qpid.server.security.auth.UsernamePrincipal;
import org.apache.qpid.server.security.auth.sasl.plain.PlainAdapterSaslServer;
import org.apache.qpid.server.security.auth.sasl.scram.ScramSaslServer;
public abstract class AbstractScramAuthenticationManager<X extends AbstractScramAuthenticationManager<X>>
- extends AbstractAuthenticationManager<X>
+ extends ConfigModelPasswordManagingAuthenticationProvider<X>
implements PasswordCredentialManagingAuthenticationProvider<X>
{
- static final Charset ASCII = Charset.forName("ASCII");
public static final String PLAIN = "PLAIN";
private final SecureRandom _random = new SecureRandom();
private int _iterationCount = 4096;
- private Map<String, ScramAuthUser> _users = new ConcurrentHashMap<String, ScramAuthUser>();
-
protected AbstractScramAuthenticationManager(final Map<String, Object> attributes, final Broker broker)
{
@@ -103,33 +89,9 @@ public abstract class AbstractScramAuthenticationManager<X extends AbstractScram
protected abstract String getDigestName();
@Override
- public AuthenticationResult authenticate(final SaslServer server, final byte[] response)
- {
- try
- {
- // Process response from the client
- byte[] challenge = server.evaluateResponse(response != null ? response : new byte[0]);
-
- if (server.isComplete() && (challenge == null || challenge.length == 0))
- {
- final String userId = server.getAuthorizationID();
- return new AuthenticationResult(new UsernamePrincipal(userId));
- }
- else
- {
- return new AuthenticationResult(challenge, AuthenticationResult.AuthenticationStatus.CONTINUE);
- }
- }
- catch (SaslException e)
- {
- return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR, e);
- }
- }
-
- @Override
public AuthenticationResult authenticate(final String username, final String password)
{
- ScramAuthUser user = getUser(username);
+ ManagedUser user = getUser(username);
if(user != null)
{
final String[] usernamePassword = user.getPassword().split(",");
@@ -142,7 +104,7 @@ public abstract class AbstractScramAuthenticationManager<X extends AbstractScram
return new AuthenticationResult(new UsernamePrincipal(username));
}
}
- catch (SaslException e)
+ catch (IllegalArgumentException e)
{
return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR,e);
}
@@ -162,7 +124,7 @@ public abstract class AbstractScramAuthenticationManager<X extends AbstractScram
public byte[] getSalt(final String username)
{
- ScramAuthUser user = getUser(username);
+ ManagedUser user = getUser(username);
if(user == null)
{
@@ -183,7 +145,7 @@ public abstract class AbstractScramAuthenticationManager<X extends AbstractScram
public byte[] getSaltedPassword(final String username) throws SaslException
{
- ScramAuthUser user = getUser(username);
+ ManagedUser user = getUser(username);
if(user == null)
{
throw new SaslException("Authentication Failed");
@@ -194,14 +156,9 @@ public abstract class AbstractScramAuthenticationManager<X extends AbstractScram
}
}
- private ScramAuthUser getUser(final String username)
- {
- return _users.get(username);
- }
-
- private byte[] createSaltedPassword(byte[] salt, String password) throws SaslException
+ private byte[] createSaltedPassword(byte[] salt, String password)
{
- Mac mac = createSha1Hmac(password.getBytes(ASCII));
+ Mac mac = createShaHmac(password.getBytes(ASCII));
mac.update(salt);
mac.update(INT_1);
@@ -222,8 +179,7 @@ public abstract class AbstractScramAuthenticationManager<X extends AbstractScram
}
- private Mac createSha1Hmac(final byte[] keyBytes)
- throws SaslException
+ private Mac createShaHmac(final byte[] keyBytes)
{
try
{
@@ -232,132 +188,16 @@ public abstract class AbstractScramAuthenticationManager<X extends AbstractScram
mac.init(key);
return mac;
}
- catch (NoSuchAlgorithmException e)
- {
- throw new SaslException(e.getMessage(), e);
- }
- catch (InvalidKeyException e)
+ catch (NoSuchAlgorithmException | InvalidKeyException e)
{
- throw new SaslException(e.getMessage(), e);
+ throw new IllegalArgumentException(e.getMessage(), e);
}
}
protected abstract String getHmacName();
@Override
- public boolean createUser(final String username, final String password, final Map<String, String> attributes)
- {
- return runTask(new Task<Boolean>()
- {
- @Override
- public Boolean execute()
- {
- getSecurityManager().authoriseUserOperation(Operation.CREATE, username);
- if (_users.containsKey(username))
- {
- throw new IllegalArgumentException("User '" + username + "' already exists");
- }
- try
- {
- Map<String, Object> userAttrs = new HashMap<String, Object>();
- userAttrs.put(User.ID, UUID.randomUUID());
- userAttrs.put(User.NAME, username);
- userAttrs.put(User.PASSWORD, createStoredPassword(password));
- userAttrs.put(User.TYPE, ScramAuthUser.SCRAM_USER_TYPE);
- ScramAuthUser user = new ScramAuthUser(userAttrs, AbstractScramAuthenticationManager.this);
- user.create();
-
- return true;
- }
- catch (SaslException e)
- {
- throw new IllegalArgumentException(e);
- }
- }
- });
- }
-
- org.apache.qpid.server.security.SecurityManager getSecurityManager()
- {
- return getBroker().getSecurityManager();
- }
-
- @Override
- public void deleteUser(final String user) throws AccountNotFoundException
- {
- runTask(new VoidTaskWithException<AccountNotFoundException>()
- {
- @Override
- public void execute() throws AccountNotFoundException
- {
- final ScramAuthUser authUser = getUser(user);
- if(authUser != null)
- {
- authUser.delete();
- }
- else
- {
- throw new AccountNotFoundException("No such user: '" + user + "'");
- }
- }
- });
- }
-
- @Override
- public void setPassword(final String username, final String password) throws AccountNotFoundException
- {
- runTask(new VoidTaskWithException<AccountNotFoundException>()
- {
- @Override
- public void execute() throws AccountNotFoundException
- {
-
- final ScramAuthUser authUser = getUser(username);
- if (authUser != null)
- {
- authUser.setPassword(password);
- }
- else
- {
- throw new AccountNotFoundException("No such user: '" + username + "'");
- }
- }
- });
-
- }
-
- @Override
- public Map<String, Map<String, String>> getUsers()
- {
- return runTask(new Task<Map<String, Map<String, String>>>()
- {
- @Override
- public Map<String, Map<String, String>> execute()
- {
-
- Map<String, Map<String, String>> users = new HashMap<String, Map<String, String>>();
- for (String user : _users.keySet())
- {
- users.put(user, Collections.<String, String>emptyMap());
- }
- return users;
- }
- });
- }
-
- @Override
- public void reload() throws IOException
- {
-
- }
-
- @Override
- public void recoverUser(final User user)
- {
- _users.put(user.getName(), (ScramAuthUser) user);
- }
-
- protected String createStoredPassword(final String password) throws SaslException
+ protected String createStoredPassword(final String password)
{
byte[] salt = new byte[32];
_random.nextBytes(salt);
@@ -366,33 +206,11 @@ public abstract class AbstractScramAuthenticationManager<X extends AbstractScram
}
@Override
- public <C extends ConfiguredObject> C addChild(final Class<C> childClass,
- final Map<String, Object> attributes,
- final ConfiguredObject... otherParents)
+ void validateUser(final ManagedUser managedUser)
{
- if(childClass == User.class)
+ if(!ASCII.newEncoder().canEncode(managedUser.getName()))
{
- String username = (String) attributes.get("name");
- String password = (String) attributes.get("password");
-
- if(createUser(username, password,null))
- {
- @SuppressWarnings("unchecked")
- C user = (C) _users.get(username);
- return user;
- }
- else
- {
- return null;
-
- }
+ throw new IllegalArgumentException("User names are restricted to characters in the ASCII charset");
}
- return super.addChild(childClass, attributes, otherParents);
}
-
- Map<String, ScramAuthUser> getUserMap()
- {
- return _users;
- }
-
}
diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ConfigModelPasswordManagingAuthenticationProvider.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ConfigModelPasswordManagingAuthenticationProvider.java
new file mode 100644
index 0000000000..5126e6978d
--- /dev/null
+++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ConfigModelPasswordManagingAuthenticationProvider.java
@@ -0,0 +1,229 @@
+/*
+ *
+ * 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.io.IOException;
+import java.nio.charset.Charset;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.security.auth.login.AccountNotFoundException;
+import javax.security.sasl.SaslException;
+import javax.security.sasl.SaslServer;
+
+import org.apache.qpid.server.configuration.updater.Task;
+import org.apache.qpid.server.configuration.updater.VoidTaskWithException;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.PasswordCredentialManagingAuthenticationProvider;
+import org.apache.qpid.server.model.User;
+import org.apache.qpid.server.security.SecurityManager;
+import org.apache.qpid.server.security.access.Operation;
+import org.apache.qpid.server.security.auth.AuthenticationResult;
+import org.apache.qpid.server.security.auth.UsernamePrincipal;
+
+public abstract class ConfigModelPasswordManagingAuthenticationProvider<X extends ConfigModelPasswordManagingAuthenticationProvider<X>>
+ extends AbstractAuthenticationManager<X>
+ implements PasswordCredentialManagingAuthenticationProvider<X>
+{
+ static final Charset ASCII = Charset.forName("ASCII");
+ protected Map<String, ManagedUser> _users = new ConcurrentHashMap<>();
+
+ protected ConfigModelPasswordManagingAuthenticationProvider(final Map<String, Object> attributes,
+ final Broker broker)
+ {
+ super(attributes, broker);
+ }
+
+ ManagedUser getUser(final String username)
+ {
+ return _users.get(username);
+ }
+
+ @Override
+ public boolean createUser(final String username, final String password, final Map<String, String> attributes)
+ {
+ return runTask(new Task<Boolean>()
+ {
+ @Override
+ public Boolean execute()
+ {
+ getSecurityManager().authoriseUserOperation(Operation.CREATE, username);
+ if (_users.containsKey(username))
+ {
+ throw new IllegalArgumentException("User '" + username + "' already exists");
+ }
+
+ Map<String, Object> userAttrs = new HashMap<>();
+ userAttrs.put(User.ID, UUID.randomUUID());
+ userAttrs.put(User.NAME, username);
+ userAttrs.put(User.PASSWORD, createStoredPassword(password));
+ userAttrs.put(User.TYPE, ManagedUser.MANAGED_USER_TYPE);
+ ManagedUser user = new ManagedUser(userAttrs, ConfigModelPasswordManagingAuthenticationProvider.this);
+ user.create();
+
+ return true;
+
+ }
+ });
+ }
+
+ SecurityManager getSecurityManager()
+ {
+ return getBroker().getSecurityManager();
+ }
+
+ @Override
+ public void deleteUser(final String user) throws AccountNotFoundException
+ {
+ runTask(new VoidTaskWithException<AccountNotFoundException>()
+ {
+ @Override
+ public void execute() throws AccountNotFoundException
+ {
+ final ManagedUser authUser = getUser(user);
+ if(authUser != null)
+ {
+ authUser.delete();
+ }
+ else
+ {
+ throw new AccountNotFoundException("No such user: '" + user + "'");
+ }
+ }
+ });
+ }
+
+ @Override
+ public Map<String, Map<String, String>> getUsers()
+ {
+ return runTask(new Task<Map<String, Map<String, String>>>()
+ {
+ @Override
+ public Map<String, Map<String, String>> execute()
+ {
+
+ Map<String, Map<String, String>> users = new HashMap<>();
+ for (String user : _users.keySet())
+ {
+ users.put(user, Collections.<String, String>emptyMap());
+ }
+ return users;
+ }
+ });
+ }
+
+ @Override
+ public void reload() throws IOException
+ {
+
+ }
+
+ @Override
+ public void recoverUser(final User user)
+ {
+ _users.put(user.getName(), (ManagedUser) user);
+ }
+
+ @Override
+ public void setPassword(final String username, final String password) throws AccountNotFoundException
+ {
+ runTask(new VoidTaskWithException<AccountNotFoundException>()
+ {
+ @Override
+ public void execute() throws AccountNotFoundException
+ {
+
+ final ManagedUser authUser = getUser(username);
+ if (authUser != null)
+ {
+ authUser.setPassword(password);
+ }
+ else
+ {
+ throw new AccountNotFoundException("No such user: '" + username + "'");
+ }
+ }
+ });
+
+ }
+
+ @Override
+ public AuthenticationResult authenticate(final SaslServer server, final byte[] response)
+ {
+ try
+ {
+ // Process response from the client
+ byte[] challenge = server.evaluateResponse(response != null ? response : new byte[0]);
+
+ if (server.isComplete() && (challenge == null || challenge.length == 0))
+ {
+ final String userId = server.getAuthorizationID();
+ return new AuthenticationResult(new UsernamePrincipal(userId));
+ }
+ else
+ {
+ return new AuthenticationResult(challenge, AuthenticationResult.AuthenticationStatus.CONTINUE);
+ }
+ }
+ catch (SaslException e)
+ {
+ return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR, e);
+ }
+ }
+
+ protected abstract String createStoredPassword(String password);
+
+ Map<String, ManagedUser> getUserMap()
+ {
+ return _users;
+ }
+
+ @Override
+ public <C extends ConfiguredObject> C addChild(final Class<C> childClass,
+ final Map<String, Object> attributes,
+ final ConfiguredObject... otherParents)
+ {
+ if(childClass == User.class)
+ {
+ String username = (String) attributes.get("name");
+ String password = (String) attributes.get("password");
+
+ if(createUser(username, password,null))
+ {
+ @SuppressWarnings("unchecked")
+ C user = (C) getUser(username);
+ return user;
+ }
+ else
+ {
+ return null;
+
+ }
+ }
+ return super.addChild(childClass, attributes, otherParents);
+ }
+
+ abstract void validateUser(final ManagedUser managedUser);
+}
diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/MD5AuthenticationProvider.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/MD5AuthenticationProvider.java
new file mode 100644
index 0000000000..cdb2f3dcc7
--- /dev/null
+++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/MD5AuthenticationProvider.java
@@ -0,0 +1,227 @@
+/*
+ *
+ * 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.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.sasl.AuthorizeCallback;
+import javax.security.sasl.SaslException;
+import javax.security.sasl.SaslServer;
+import javax.xml.bind.DatatypeConverter;
+
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.ManagedObject;
+import org.apache.qpid.server.model.ManagedObjectFactoryConstructor;
+import org.apache.qpid.server.security.auth.AuthenticationResult;
+import org.apache.qpid.server.security.auth.UsernamePrincipal;
+import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HashedSaslServer;
+import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HexSaslServer;
+import org.apache.qpid.server.security.auth.sasl.plain.PlainAdapterSaslServer;
+import org.apache.qpid.server.security.auth.sasl.plain.PlainSaslServer;
+import org.apache.qpid.server.util.ServerScopedRuntimeException;
+
+@ManagedObject( category = false, type = "MD5" )
+public class MD5AuthenticationProvider
+ extends ConfigModelPasswordManagingAuthenticationProvider<MD5AuthenticationProvider>
+{
+ private final List<String> _mechanisms = Collections.unmodifiableList(Arrays.asList(PlainSaslServer.MECHANISM,
+ CRAMMD5HashedSaslServer.MECHANISM,
+ CRAMMD5HexSaslServer.MECHANISM));
+
+
+ @ManagedObjectFactoryConstructor
+ protected MD5AuthenticationProvider(final Map<String, Object> attributes, final Broker broker)
+ {
+ super(attributes, broker);
+ }
+
+ @Override
+ protected String createStoredPassword(final String password)
+ {
+ byte[] data = password.getBytes(StandardCharsets.UTF_8);
+ MessageDigest md = null;
+ try
+ {
+ md = MessageDigest.getInstance("MD5");
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new ServerScopedRuntimeException("MD5 not supported although Java compliance requires it");
+ }
+
+ md.update(data);
+ return DatatypeConverter.printBase64Binary(md.digest());
+ }
+
+ @Override
+ void validateUser(final ManagedUser managedUser)
+ {
+ }
+
+ @Override
+ public List<String> getMechanisms()
+ {
+ return _mechanisms;
+ }
+
+ @Override
+ public SaslServer createSaslServer(final String mechanism,
+ final String localFQDN,
+ final Principal externalPrincipal)
+ throws SaslException
+ {
+ if(PlainSaslServer.MECHANISM.equals(mechanism))
+ {
+ return new PlainAdapterSaslServer(this);
+ }
+ else if(CRAMMD5HashedSaslServer.MECHANISM.equals(mechanism))
+ {
+ //simply delegate to the built in CRAM-MD5 SaslServer
+ return new CRAMMD5HashedSaslServer(mechanism, "AMQP", localFQDN, null, new MD5Callbackhandler(false));
+ }
+ else if(CRAMMD5HexSaslServer.MECHANISM.equals(mechanism))
+ {
+ //simply delegate to the built in CRAM-MD5 SaslServer
+ return new CRAMMD5HashedSaslServer(mechanism, "AMQP", localFQDN, null, new MD5Callbackhandler(true));
+ }
+ else
+ {
+ throw new SaslException("Unsupported mechanism: " + mechanism);
+ }
+ }
+
+ @Override
+ public AuthenticationResult authenticate(final String username, final String password)
+ {
+ ManagedUser user = getUser(username);
+ AuthenticationResult result;
+ if(user != null && user.getPassword().equals(createStoredPassword(password)))
+ {
+ result = new AuthenticationResult(new UsernamePrincipal(username));
+ }
+ else
+ {
+ result = new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR);
+ }
+ return result;
+ }
+ private static final char[] HEX_CHARACTERS =
+ {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+
+ private class MD5Callbackhandler implements CallbackHandler
+ {
+ private final boolean _hexify;
+ private String _username;
+
+ public MD5Callbackhandler(final boolean hexify)
+ {
+ _hexify = hexify;
+ }
+
+ public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException
+ {
+ List<Callback> callbackList = new ArrayList<>(Arrays.asList(callbacks));
+ Iterator<Callback> iter = callbackList.iterator();
+ while(iter.hasNext())
+ {
+ Callback callback = iter.next();
+ if (callback instanceof NameCallback)
+ {
+ _username = ((NameCallback) callback).getDefaultName();
+ iter.remove();
+ break;
+ }
+ }
+
+ if(_username != null)
+ {
+ iter = callbackList.iterator();
+ while (iter.hasNext())
+ {
+ Callback callback = iter.next();
+ if (callback instanceof PasswordCallback)
+ {
+ iter.remove();
+ ManagedUser user = getUser(_username);
+ if(user != null)
+ {
+ String passwordData = user.getPassword();
+ byte[] passwordBytes = DatatypeConverter.parseBase64Binary(passwordData);
+ char[] password;
+ if(_hexify)
+ {
+ password = new char[passwordBytes.length];
+
+ for(int i = 0; i < passwordBytes.length; i--)
+ {
+ password[2*i] = HEX_CHARACTERS[(((int)passwordBytes[i]) & 0xf0)>>4];
+ password[(2*i)+1] = HEX_CHARACTERS[(((int)passwordBytes[i]) & 0x0f)];
+ }
+ }
+ else
+ {
+ password = new char[passwordBytes.length];
+ for(int i = 0; i < passwordBytes.length; i++)
+ {
+ password[i] = (char) passwordBytes[i];
+ }
+ }
+ ((PasswordCallback) callback).setPassword(password);
+ }
+ else
+ {
+ ((PasswordCallback) callback).setPassword(null);
+ }
+ break;
+ }
+ }
+ }
+
+ for (Callback callback : callbackList)
+ {
+
+ if (callback instanceof AuthorizeCallback)
+ {
+ ((AuthorizeCallback) callback).setAuthorized(true);
+ }
+ else
+ {
+ throw new UnsupportedCallbackException(callback);
+ }
+ }
+ }
+ }
+}
diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ScramAuthUser.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ManagedUser.java
index b3de1d1f17..c8884e15a8 100644
--- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ScramAuthUser.java
+++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ManagedUser.java
@@ -27,8 +27,6 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Set;
-import javax.security.sasl.SaslException;
-
import org.apache.qpid.server.configuration.updater.VoidTask;
import org.apache.qpid.server.model.AbstractConfiguredObject;
import org.apache.qpid.server.model.ConfiguredObject;
@@ -41,24 +39,21 @@ import org.apache.qpid.server.model.StateTransition;
import org.apache.qpid.server.model.User;
import org.apache.qpid.server.security.access.Operation;
-@ManagedObject( category = false, type = ScramAuthUser.SCRAM_USER_TYPE)
-class ScramAuthUser extends AbstractConfiguredObject<ScramAuthUser> implements User<ScramAuthUser>
+@ManagedObject( category = false, type = ManagedUser.MANAGED_USER_TYPE)
+class ManagedUser extends AbstractConfiguredObject<ManagedUser> implements User<ManagedUser>
{
- public static final String SCRAM_USER_TYPE = "scram";
+ public static final String MANAGED_USER_TYPE = "managed";
- private AbstractScramAuthenticationManager _authenticationManager;
+ private ConfigModelPasswordManagingAuthenticationProvider<?> _authenticationManager;
@ManagedAttributeField
private String _password;
@ManagedObjectFactoryConstructor
- ScramAuthUser(final Map<String, Object> attributes, AbstractScramAuthenticationManager parent)
+ ManagedUser(final Map<String, Object> attributes, ConfigModelPasswordManagingAuthenticationProvider<?> parent)
{
super(parentsMap(parent), attributes);
_authenticationManager = parent;
- if(!ScramSHA1AuthenticationManager.ASCII.newEncoder().canEncode(getName()))
- {
- throw new IllegalArgumentException("Scram SHA1 user names are restricted to characters in the ASCII charset");
- }
+
setState(State.ACTIVE);
}
@@ -73,6 +68,7 @@ class ScramAuthUser extends AbstractConfiguredObject<ScramAuthUser> implements U
public void onValidate()
{
super.onValidate();
+ _authenticationManager.validateUser(this);
if(!isDurable())
{
throw new IllegalArgumentException(getClass().getSimpleName() + " must be durable");
@@ -122,17 +118,11 @@ class ScramAuthUser extends AbstractConfiguredObject<ScramAuthUser> implements U
if (attributes.containsKey(User.PASSWORD)
&& !newPassword.equals(getActualAttributes().get(User.PASSWORD)))
{
- try
- {
- modifiedAttributes.put(User.PASSWORD,
- _authenticationManager.createStoredPassword(newPassword));
- }
- catch (SaslException e)
- {
- throw new IllegalArgumentException(e);
- }
+ modifiedAttributes.put(User.PASSWORD,
+ _authenticationManager.createStoredPassword(newPassword));
+
}
- ScramAuthUser.super.setAttributes(modifiedAttributes);
+ ManagedUser.super.setAttributes(modifiedAttributes);
}
});
@@ -150,15 +140,9 @@ class ScramAuthUser extends AbstractConfiguredObject<ScramAuthUser> implements U
{
_authenticationManager.getSecurityManager().authoriseUserOperation(Operation.UPDATE, getName());
- try
- {
- changeAttribute(User.PASSWORD, getAttribute(User.PASSWORD), _authenticationManager.createStoredPassword(
- password));
- }
- catch (SaslException e)
- {
- throw new IllegalArgumentException(e);
- }
+ changeAttribute(User.PASSWORD, getAttribute(User.PASSWORD),
+ _authenticationManager.createStoredPassword(password));
+
}
@Override
@@ -170,7 +154,7 @@ class ScramAuthUser extends AbstractConfiguredObject<ScramAuthUser> implements U
@Override
public Map<String, Object> getPreferences()
{
- PreferencesProvider preferencesProvider = _authenticationManager.getPreferencesProvider();
+ PreferencesProvider<?> preferencesProvider = _authenticationManager.getPreferencesProvider();
if (preferencesProvider == null)
{
return null;
@@ -192,7 +176,7 @@ class ScramAuthUser extends AbstractConfiguredObject<ScramAuthUser> implements U
@Override
public Map<String, Object> setPreferences(Map<String, Object> preferences)
{
- PreferencesProvider preferencesProvider = _authenticationManager.getPreferencesProvider();
+ PreferencesProvider<?> preferencesProvider = _authenticationManager.getPreferencesProvider();
if (preferencesProvider == null)
{
return null;
diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/PlainAuthenticationProvider.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/PlainAuthenticationProvider.java
new file mode 100644
index 0000000000..5c79253ebb
--- /dev/null
+++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/PlainAuthenticationProvider.java
@@ -0,0 +1,176 @@
+/*
+ *
+ * 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.io.IOException;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.sasl.AuthorizeCallback;
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslException;
+import javax.security.sasl.SaslServer;
+
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.ManagedObject;
+import org.apache.qpid.server.model.ManagedObjectFactoryConstructor;
+import org.apache.qpid.server.security.auth.AuthenticationResult;
+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.PlainAdapterSaslServer;
+import org.apache.qpid.server.security.auth.sasl.plain.PlainSaslServer;
+
+@ManagedObject( category = false, type = "Plain" )
+public class PlainAuthenticationProvider
+ extends ConfigModelPasswordManagingAuthenticationProvider<PlainAuthenticationProvider>
+{
+ private final List<String> _mechanisms = Collections.unmodifiableList(Arrays.asList(PlainSaslServer.MECHANISM,
+ CRAMMD5Initialiser.MECHANISM));
+
+
+ @ManagedObjectFactoryConstructor
+ protected PlainAuthenticationProvider(final Map<String, Object> attributes, final Broker broker)
+ {
+ super(attributes, broker);
+ }
+
+ @Override
+ protected String createStoredPassword(final String password)
+ {
+ return password;
+ }
+
+ @Override
+ void validateUser(final ManagedUser managedUser)
+ {
+ // NOOP
+ }
+
+ @Override
+ public List<String> getMechanisms()
+ {
+ return _mechanisms;
+ }
+
+ @Override
+ public SaslServer createSaslServer(final String mechanism,
+ final String localFQDN,
+ final Principal externalPrincipal)
+ throws SaslException
+ {
+ if(PlainSaslServer.MECHANISM.equals(mechanism))
+ {
+ return new PlainAdapterSaslServer(this);
+ }
+ else if(CRAMMD5Initialiser.MECHANISM.equals(mechanism))
+ {
+ //simply delegate to the built in CRAM-MD5 SaslServer
+ return Sasl.createSaslServer(mechanism, "AMQP", localFQDN, null, new ServerCallbackHandler());
+ }
+ else
+ {
+ throw new SaslException("Unsupported mechanism: " + mechanism);
+ }
+ }
+
+ @Override
+ public AuthenticationResult authenticate(final String username, final String password)
+ {
+ ManagedUser user = getUser(username);
+ AuthenticationResult result;
+ if(user != null && user.getPassword().equals(password))
+ {
+ result = new AuthenticationResult(new UsernamePrincipal(username));
+ }
+ else
+ {
+ result = new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR);
+ }
+ return result;
+ }
+
+ private class ServerCallbackHandler implements CallbackHandler
+ {
+ String _username;
+
+ public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException
+ {
+ List<Callback> callbackList = new ArrayList<>(Arrays.asList(callbacks));
+ Iterator<Callback> iter = callbackList.iterator();
+ while(iter.hasNext())
+ {
+ Callback callback = iter.next();
+ if (callback instanceof NameCallback)
+ {
+ _username = ((NameCallback) callback).getDefaultName();
+ iter.remove();
+ break;
+ }
+ }
+
+ if(_username != null)
+ {
+ iter = callbackList.iterator();
+ while (iter.hasNext())
+ {
+ Callback callback = iter.next();
+ if (callback instanceof PasswordCallback)
+ {
+ iter.remove();
+ ManagedUser user = getUser(_username);
+ if(user != null)
+ {
+ ((PasswordCallback) callback).setPassword(user.getPassword().toCharArray());
+ }
+ else
+ {
+ ((PasswordCallback) callback).setPassword(null);
+ }
+ break;
+ }
+ }
+ }
+
+ for (Callback callback : callbackList)
+ {
+
+ if (callback instanceof AuthorizeCallback)
+ {
+ ((AuthorizeCallback) callback).setAuthorized(true);
+ }
+ else
+ {
+ throw new UnsupportedCallbackException(callback);
+ }
+ }
+ }
+ }
+}
diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/BrokerStoreUpgraderAndRecoverer.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/BrokerStoreUpgraderAndRecoverer.java
index 157229b30b..08440826be 100644
--- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/BrokerStoreUpgraderAndRecoverer.java
+++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/store/BrokerStoreUpgraderAndRecoverer.java
@@ -229,6 +229,13 @@ public class BrokerStoreUpgraderAndRecoverer
createAliasRecord(record, "hostnameAlias", "hostnameAlias");
}
+ else if(record.getType().equals("User") && "scram".equals(record.getAttributes().get("type")) )
+ {
+ Map<String, Object> updatedAttributes = new HashMap<String, Object>(record.getAttributes());
+ updatedAttributes.put("type", "managed");
+ record = new ConfiguredObjectRecordImpl(record.getId(), record.getType(), updatedAttributes, record.getParents());
+ getUpdateMap().put(record.getId(), record);
+ }
else if (record.getType().equals("Broker"))
{
record = upgradeRootRecord(record);
diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/tools/security/Passwd.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/tools/security/Passwd.java
deleted file mode 100644
index cd833c89c4..0000000000
--- a/qpid/java/broker-core/src/main/java/org/apache/qpid/tools/security/Passwd.java
+++ /dev/null
@@ -1,70 +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.tools.security;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.Charset;
-import java.security.DigestException;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-
-import org.apache.commons.codec.binary.Base64;
-
-/**
- * Utility to generate user:encodedPassword string for use in md5passwd
- */
-public class Passwd
-{
- public static void main(String args[]) throws NoSuchAlgorithmException, DigestException, IOException
- {
- if (args.length != 2)
- {
- System.out.println("Passwd <username> <password>");
- System.exit(0);
- }
-
- Passwd passwd = new Passwd();
- String output = passwd.getOutput(args[0], args[1]);
- System.out.println(output);
- }
-
- public String getOutput(String userName, String password) throws UnsupportedEncodingException, NoSuchAlgorithmException
- {
- byte[] data = password.getBytes("utf-8");
-
- MessageDigest md = MessageDigest.getInstance("MD5");
-
- for (byte b : data)
- {
- md.update(b);
- }
-
- byte[] digest = md.digest();
-
- Base64 b64 = new Base64();
-
- byte[] encoded = b64.encode(digest);
-
- String encodedStr = new String(encoded, Charset.forName("utf-8"));
- return userName + ":" + encodedStr;
- }
-}
diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/SubjectCreatorTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/SubjectCreatorTest.java
index 5366e6d8bf..8e814745b6 100644
--- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/SubjectCreatorTest.java
+++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/SubjectCreatorTest.java
@@ -44,10 +44,10 @@ public class SubjectCreatorTest extends TestCase
private static final String USERNAME = "username";
private static final String PASSWORD = "password";
- private AuthenticationProvider _authenticationProvider = mock(AuthenticationProvider.class);
+ private AuthenticationProvider<?> _authenticationProvider = mock(AuthenticationProvider.class);
- private GroupProvider _groupManager1 = mock(GroupProvider.class);
- private GroupProvider _groupManager2 = mock(GroupProvider.class);
+ private GroupProvider<?> _groupManager1 = mock(GroupProvider.class);
+ private GroupProvider<?> _groupManager2 = mock(GroupProvider.class);
private Principal _userPrincipal = mock(Principal.class);
private Principal _group1 = mock(Principal.class);
@@ -64,7 +64,7 @@ public class SubjectCreatorTest extends TestCase
when(_groupManager1.getGroupPrincipalsForUser(USERNAME)).thenReturn(Collections.singleton(_group1));
when(_groupManager2.getGroupPrincipalsForUser(USERNAME)).thenReturn(Collections.singleton(_group2));
- _subjectCreator = new SubjectCreator(_authenticationProvider, new HashSet<GroupProvider>(Arrays.asList(_groupManager1, _groupManager2)),
+ _subjectCreator = new SubjectCreator(_authenticationProvider, new HashSet<GroupProvider<?>>(Arrays.asList(_groupManager1, _groupManager2)),
false);
_authenticationResult = new AuthenticationResult(_userPrincipal);
when(_authenticationProvider.authenticate(USERNAME, PASSWORD)).thenReturn(_authenticationResult);
diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/tools/security/PasswdTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/MD5AuthenticationManagerTest.java
index b2a7234c8a..aecd318937 100644
--- a/qpid/java/broker-core/src/test/java/org/apache/qpid/tools/security/PasswdTest.java
+++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/MD5AuthenticationManagerTest.java
@@ -1,4 +1,5 @@
/*
+ *
* 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
@@ -15,24 +16,38 @@
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
+ *
*/
-package org.apache.qpid.tools.security;
+package org.apache.qpid.server.security.auth.manager;
-import junit.framework.TestCase;
+import java.util.Map;
-public class PasswdTest extends TestCase
+public class MD5AuthenticationManagerTest extends ManagedAuthenticationManagerTestBase
{
- public void testUserGuestAndPasswordGuest() throws Exception
+ @Override
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ }
+
+ @Override
+ protected ConfigModelPasswordManagingAuthenticationProvider<?> createAuthManager(final Map<String, Object> attributesMap)
{
- Passwd passwd = new Passwd();
- String output = passwd.getOutput("guest", "guest");
- assertEquals("guest:CE4DQ6BIb/BVMN9scFyLtA==", output);
+ return new MD5AuthenticationProvider(attributesMap, getBroker());
}
- public void testUser1AndPasswordFoo() throws Exception
+ @Override
+ protected boolean isPlain()
{
- Passwd passwd = new Passwd();
- String output = passwd.getOutput("user1", "foo");
- assertEquals("user1:rL0Y20zC+Fzt72VPzMSk2A==", output);
+ return false;
}
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ super.tearDown();
+ }
+
+
+
}
diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/ManagedAuthenticationManagerTestBase.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/ManagedAuthenticationManagerTestBase.java
new file mode 100644
index 0000000000..dd92d3ebca
--- /dev/null
+++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/ManagedAuthenticationManagerTestBase.java
@@ -0,0 +1,252 @@
+/*
+ *
+ * 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 static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.security.auth.login.AccountNotFoundException;
+import javax.security.sasl.SaslException;
+import javax.security.sasl.SaslServer;
+
+import org.apache.qpid.server.configuration.updater.CurrentThreadTaskExecutor;
+import org.apache.qpid.server.configuration.updater.TaskExecutor;
+import org.apache.qpid.server.model.AuthenticationProvider;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.User;
+import org.apache.qpid.server.security.SecurityManager;
+import org.apache.qpid.server.security.SubjectCreator;
+import org.apache.qpid.server.security.auth.AuthenticationResult;
+import org.apache.qpid.server.util.BrokerTestHelper;
+import org.apache.qpid.test.utils.QpidTestCase;
+
+abstract class ManagedAuthenticationManagerTestBase extends QpidTestCase
+{
+ private ConfigModelPasswordManagingAuthenticationProvider<?> _authManager;
+
+
+ private Broker _broker;
+ private SecurityManager _securityManager;
+ private TaskExecutor _executor;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ _executor = new CurrentThreadTaskExecutor();
+ _executor.start();
+ _broker = BrokerTestHelper.createBrokerMock();
+ _securityManager = mock(SecurityManager.class);
+ when(_broker.getTaskExecutor()).thenReturn(_executor);
+ when(_broker.getSecurityManager()).thenReturn(_securityManager);
+ final Map<String, Object> attributesMap = new HashMap<String, Object>();
+ attributesMap.put(AuthenticationProvider.NAME, getTestName());
+ attributesMap.put(AuthenticationProvider.ID, UUID.randomUUID());
+ _authManager = createAuthManager(attributesMap);
+ _authManager.open();
+ }
+
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ _executor.stop();
+ super.tearDown();
+ }
+
+ protected abstract ConfigModelPasswordManagingAuthenticationProvider createAuthManager(final Map<String, Object> attributesMap);
+
+ public Broker getBroker()
+ {
+ return _broker;
+ }
+
+ public ConfigModelPasswordManagingAuthenticationProvider<?> getAuthManager()
+ {
+ return _authManager;
+ }
+
+
+ public void testMechanisms()
+ {
+ SubjectCreator insecureCreator = _authManager.getSubjectCreator(false);
+ assertFalse("PLAIN authentication should not be available on an insecure connection", insecureCreator.getMechanisms().contains("PLAIN"));
+ SubjectCreator secureCreator = _authManager.getSubjectCreator(true);
+ assertTrue("PLAIN authentication should be available on a secure connection", secureCreator.getMechanisms().contains("PLAIN"));
+
+ try
+ {
+ SaslServer saslServer = secureCreator.createSaslServer("PLAIN", "127.0.0.1", null);
+ assertNotNull(saslServer);
+ }
+ catch (SaslException e)
+ {
+ fail("Unable to create a SaslServer for PLAIN authentication on a secure connection" + e.getMessage());
+ }
+
+ try
+ {
+ SaslServer saslServer = insecureCreator.createSaslServer("PLAIN", "127.0.0.1", null);
+ fail("Erroneously created a SaslServer for PLAIN authentication on an insecure connection");
+ }
+ catch (SaslException e)
+ {
+ // Pass
+ }
+
+ }
+
+ public void testAddChildAndThenDelete()
+ {
+ // No children should be present before the test starts
+ assertEquals("No users should be present before the test starts", 0, _authManager.getChildren(User.class).size());
+ assertEquals("No users should be present before the test starts", 0, _authManager.getUsers().size());
+
+ final Map<String, Object> childAttrs = new HashMap<String, Object>();
+
+ childAttrs.put(User.NAME, getTestName());
+ childAttrs.put(User.PASSWORD, "password");
+ User user = _authManager.addChild(User.class, childAttrs);
+ assertNotNull("User should be created but addChild returned null", user);
+ assertEquals(getTestName(), user.getName());
+ if(!isPlain())
+ {
+ // password shouldn't actually be the given string, but instead hashed value
+ assertFalse("Password shouldn't actually be the given string, but instead hashed value",
+ "password".equals(user.getPassword()));
+ }
+
+ AuthenticationResult authResult =
+ _authManager.authenticate(getTestName(), "password");
+
+ assertEquals("User should authenticate with given password", AuthenticationResult.AuthenticationStatus.SUCCESS, authResult.getStatus());
+
+ assertEquals("Manager should have exactly one user child",1, _authManager.getChildren(User.class).size());
+ assertEquals("Manager should have exactly one user child",1, _authManager.getUsers().size());
+
+
+ user.delete();
+
+ assertEquals("No users should be present after child deletion", 0, _authManager.getChildren(User.class).size());
+
+
+ authResult = _authManager.authenticate(getTestName(), "password");
+ assertEquals("User should no longer authenticate with given password", AuthenticationResult.AuthenticationStatus.ERROR, authResult.getStatus());
+
+ }
+
+ public void testCreateUser()
+ {
+ assertEquals("No users should be present before the test starts", 0, _authManager.getChildren(User.class).size());
+ assertTrue(_authManager.createUser(getTestName(), "password", Collections.<String, String>emptyMap()));
+ assertEquals("Manager should have exactly one user child",1, _authManager.getChildren(User.class).size());
+ User user = _authManager.getChildren(User.class).iterator().next();
+ assertEquals(getTestName(), user.getName());
+ if(!isPlain())
+ {
+ // password shouldn't actually be the given string, but instead salt and the hashed value
+ assertFalse("Password shouldn't actually be the given string, but instead salt and the hashed value",
+ "password".equals(user.getPassword()));
+ }
+ final Map<String, Object> childAttrs = new HashMap<String, Object>();
+
+ childAttrs.put(User.NAME, getTestName());
+ childAttrs.put(User.PASSWORD, "password");
+ try
+ {
+ user = _authManager.addChild(User.class, childAttrs);
+ fail("Should not be able to create a second user with the same name");
+ }
+ catch(IllegalArgumentException e)
+ {
+ // pass
+ }
+ try
+ {
+ _authManager.deleteUser(getTestName());
+ }
+ catch (AccountNotFoundException e)
+ {
+ fail("AccountNotFoundException thrown when none was expected: " + e.getMessage());
+ }
+ try
+ {
+ _authManager.deleteUser(getTestName());
+ fail("AccountNotFoundException not thrown when was expected");
+ }
+ catch (AccountNotFoundException e)
+ {
+ // pass
+ }
+ }
+
+ protected abstract boolean isPlain();
+
+ public void testUpdateUser()
+ {
+ assertTrue(_authManager.createUser(getTestName(), "password", Collections.<String, String>emptyMap()));
+ assertTrue(_authManager.createUser(getTestName()+"_2", "password", Collections.<String, String>emptyMap()));
+ assertEquals("Manager should have exactly two user children",2, _authManager.getChildren(User.class).size());
+
+ AuthenticationResult authResult = _authManager.authenticate(getTestName(), "password");
+
+ assertEquals("User should authenticate with given password", AuthenticationResult.AuthenticationStatus.SUCCESS, authResult.getStatus());
+ authResult = _authManager.authenticate(getTestName()+"_2", "password");
+ assertEquals("User should authenticate with given password", AuthenticationResult.AuthenticationStatus.SUCCESS, authResult.getStatus());
+
+ for(User user : _authManager.getChildren(User.class))
+ {
+ if(user.getName().equals(getTestName()))
+ {
+ user.setAttributes(Collections.singletonMap(User.PASSWORD, "newpassword"));
+ }
+ }
+
+ authResult = _authManager.authenticate(getTestName(), "newpassword");
+ assertEquals("User should authenticate with updated password", AuthenticationResult.AuthenticationStatus.SUCCESS, authResult.getStatus());
+ authResult = _authManager.authenticate(getTestName()+"_2", "password");
+ assertEquals("User should authenticate with original password", AuthenticationResult.AuthenticationStatus.SUCCESS, authResult.getStatus());
+
+ authResult = _authManager.authenticate(getTestName(), "password");
+ assertEquals("User not authenticate with original password", AuthenticationResult.AuthenticationStatus.ERROR, authResult.getStatus());
+
+ for(User user : _authManager.getChildren(User.class))
+ {
+ if(user.getName().equals(getTestName()))
+ {
+ user.setPassword("newerpassword");
+ }
+ }
+
+ authResult = _authManager.authenticate(getTestName(), "newerpassword");
+ assertEquals("User should authenticate with updated password", AuthenticationResult.AuthenticationStatus.SUCCESS, authResult.getStatus());
+
+
+
+ }
+
+
+}
diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/PlainAuthenticationManagerTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/PlainAuthenticationManagerTest.java
new file mode 100644
index 0000000000..f7f60227db
--- /dev/null
+++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/PlainAuthenticationManagerTest.java
@@ -0,0 +1,51 @@
+/*
+ *
+ * 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.util.Map;
+
+public class PlainAuthenticationManagerTest extends ManagedAuthenticationManagerTestBase
+{
+ @Override
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ }
+
+ @Override
+ protected ConfigModelPasswordManagingAuthenticationProvider<?> createAuthManager(final Map<String, Object> attributesMap)
+ {
+ return new PlainAuthenticationProvider(attributesMap, getBroker());
+ }
+
+ @Override
+ protected boolean isPlain()
+ {
+ return true;
+ }
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ super.tearDown();
+ }
+
+}
diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/ScramSHA1AuthenticationManagerTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/ScramSHA1AuthenticationManagerTest.java
index 455b5b5ec2..9a7e59abe0 100644
--- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/ScramSHA1AuthenticationManagerTest.java
+++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/ScramSHA1AuthenticationManagerTest.java
@@ -20,213 +20,43 @@
*/
package org.apache.qpid.server.security.auth.manager;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
import java.util.Collections;
-import java.util.HashMap;
import java.util.Map;
-import java.util.UUID;
-
-import javax.security.auth.login.AccountNotFoundException;
-import javax.security.sasl.SaslException;
-import javax.security.sasl.SaslServer;
-
-import org.apache.qpid.server.configuration.updater.CurrentThreadTaskExecutor;
-import org.apache.qpid.server.configuration.updater.TaskExecutor;
-import org.apache.qpid.server.model.AuthenticationProvider;
-import org.apache.qpid.server.model.Broker;
-import org.apache.qpid.server.model.User;
-import org.apache.qpid.server.security.SecurityManager;
-import org.apache.qpid.server.security.SubjectCreator;
-import org.apache.qpid.server.security.auth.AuthenticationResult;
-import org.apache.qpid.server.util.BrokerTestHelper;
-import org.apache.qpid.test.utils.QpidTestCase;
-public class ScramSHA1AuthenticationManagerTest extends QpidTestCase
+public class ScramSHA1AuthenticationManagerTest extends ManagedAuthenticationManagerTestBase
{
- private ScramSHA1AuthenticationManager _authManager;
- private Broker _broker;
- private SecurityManager _securityManager;
- private TaskExecutor _executor;
-
@Override
public void setUp() throws Exception
{
super.setUp();
- _executor = new CurrentThreadTaskExecutor();
- _executor.start();
- _broker = BrokerTestHelper.createBrokerMock();
- _securityManager = mock(SecurityManager.class);
- when(_broker.getTaskExecutor()).thenReturn(_executor);
- when(_broker.getSecurityManager()).thenReturn(_securityManager);
- final Map<String, Object> attributesMap = new HashMap<String, Object>();
- attributesMap.put(AuthenticationProvider.NAME, getTestName());
- attributesMap.put(AuthenticationProvider.ID, UUID.randomUUID());
- _authManager = new ScramSHA1AuthenticationManager(attributesMap, _broker);
- _authManager.open();
}
@Override
- public void tearDown() throws Exception
- {
- _executor.stop();
- super.tearDown();
- }
-
- public void testMechanisms()
+ protected ConfigModelPasswordManagingAuthenticationProvider<?> createAuthManager(final Map<String, Object> attributesMap)
{
- SubjectCreator insecureCreator = _authManager.getSubjectCreator(false);
- assertFalse("PLAIN authentication should not be available on an insecure connection", insecureCreator.getMechanisms().contains("PLAIN"));
- SubjectCreator secureCreator = _authManager.getSubjectCreator(true);
- assertTrue("PLAIN authentication should be available on a secure connection", secureCreator.getMechanisms().contains("PLAIN"));
-
- try
- {
- SaslServer saslServer = secureCreator.createSaslServer("PLAIN", "127.0.0.1", null);
- assertNotNull(saslServer);
- }
- catch (SaslException e)
- {
- fail("Unable to create a SaslServer for PLAIN authentication on a secure connection" + e.getMessage());
- }
-
- try
- {
- SaslServer saslServer = insecureCreator.createSaslServer("PLAIN", "127.0.0.1", null);
- fail("Erroneously created a SaslServer for PLAIN authentication on an insecure connection");
- }
- catch (SaslException e)
- {
- // Pass
- }
-
+ return new ScramSHA1AuthenticationManager(attributesMap, getBroker());
}
- public void testAddChildAndThenDelete()
+ @Override
+ protected boolean isPlain()
{
- // No children should be present before the test starts
- assertEquals("No users should be present before the test starts", 0, _authManager.getChildren(User.class).size());
- assertEquals("No users should be present before the test starts", 0, _authManager.getUsers().size());
-
- final Map<String, Object> childAttrs = new HashMap<String, Object>();
-
- childAttrs.put(User.NAME, getTestName());
- childAttrs.put(User.PASSWORD, "password");
- User user = _authManager.addChild(User.class, childAttrs);
- assertNotNull("User should be created but addChild returned null", user);
- assertEquals(getTestName(), user.getName());
- // password shouldn't actually be the given string, but instead salt and the hashed value
- assertFalse("Password shouldn't actually be the given string, but instead salt and the hashed value", "password".equals(user.getPassword()));
-
- AuthenticationResult authResult =
- _authManager.authenticate(getTestName(), "password");
-
- assertEquals("User should authenticate with given password", AuthenticationResult.AuthenticationStatus.SUCCESS, authResult.getStatus());
-
- assertEquals("Manager should have exactly one user child",1, _authManager.getChildren(User.class).size());
- assertEquals("Manager should have exactly one user child",1, _authManager.getUsers().size());
-
-
- user.delete();
-
- assertEquals("No users should be present after child deletion", 0, _authManager.getChildren(User.class).size());
-
-
- authResult = _authManager.authenticate(getTestName(), "password");
- assertEquals("User should no longer authenticate with given password", AuthenticationResult.AuthenticationStatus.ERROR, authResult.getStatus());
-
+ return false;
}
- public void testCreateUser()
+ @Override
+ public void tearDown() throws Exception
{
- assertEquals("No users should be present before the test starts", 0, _authManager.getChildren(User.class).size());
- assertTrue(_authManager.createUser(getTestName(), "password", Collections.<String, String>emptyMap()));
- assertEquals("Manager should have exactly one user child",1, _authManager.getChildren(User.class).size());
- User user = _authManager.getChildren(User.class).iterator().next();
- assertEquals(getTestName(), user.getName());
- // password shouldn't actually be the given string, but instead salt and the hashed value
- assertFalse("Password shouldn't actually be the given string, but instead salt and the hashed value", "password".equals(user.getPassword()));
- final Map<String, Object> childAttrs = new HashMap<String, Object>();
-
- childAttrs.put(User.NAME, getTestName());
- childAttrs.put(User.PASSWORD, "password");
- try
- {
- user = _authManager.addChild(User.class, childAttrs);
- fail("Should not be able to create a second user with the same name");
- }
- catch(IllegalArgumentException e)
- {
- // pass
- }
- try
- {
- _authManager.deleteUser(getTestName());
- }
- catch (AccountNotFoundException e)
- {
- fail("AccountNotFoundException thrown when none was expected: " + e.getMessage());
- }
- try
- {
- _authManager.deleteUser(getTestName());
- fail("AccountNotFoundException not thrown when was expected");
- }
- catch (AccountNotFoundException e)
- {
- // pass
- }
+ super.tearDown();
}
- public void testUpdateUser()
- {
- assertTrue(_authManager.createUser(getTestName(), "password", Collections.<String, String>emptyMap()));
- assertTrue(_authManager.createUser(getTestName()+"_2", "password", Collections.<String, String>emptyMap()));
- assertEquals("Manager should have exactly two user children",2, _authManager.getChildren(User.class).size());
-
- AuthenticationResult authResult = _authManager.authenticate(getTestName(), "password");
-
- assertEquals("User should authenticate with given password", AuthenticationResult.AuthenticationStatus.SUCCESS, authResult.getStatus());
- authResult = _authManager.authenticate(getTestName()+"_2", "password");
- assertEquals("User should authenticate with given password", AuthenticationResult.AuthenticationStatus.SUCCESS, authResult.getStatus());
-
- for(User user : _authManager.getChildren(User.class))
- {
- if(user.getName().equals(getTestName()))
- {
- user.setAttributes(Collections.singletonMap(User.PASSWORD, "newpassword"));
- }
- }
-
- authResult = _authManager.authenticate(getTestName(), "newpassword");
- assertEquals("User should authenticate with updated password", AuthenticationResult.AuthenticationStatus.SUCCESS, authResult.getStatus());
- authResult = _authManager.authenticate(getTestName()+"_2", "password");
- assertEquals("User should authenticate with original password", AuthenticationResult.AuthenticationStatus.SUCCESS, authResult.getStatus());
-
- authResult = _authManager.authenticate(getTestName(), "password");
- assertEquals("User not authenticate with original password", AuthenticationResult.AuthenticationStatus.ERROR, authResult.getStatus());
-
- for(User user : _authManager.getChildren(User.class))
- {
- if(user.getName().equals(getTestName()))
- {
- user.setPassword("newerpassword");
- }
- }
-
- authResult = _authManager.authenticate(getTestName(), "newerpassword");
- assertEquals("User should authenticate with updated password", AuthenticationResult.AuthenticationStatus.SUCCESS, authResult.getStatus());
-
-
-
- }
public void testNonASCIIUser()
{
try
{
- _authManager.createUser(getTestName()+Character.toString((char)0xa3), "password", Collections.<String, String>emptyMap());
+ getAuthManager().createUser(getTestName() + Character.toString((char) 0xa3),
+ "password",
+ Collections.<String, String>emptyMap());
fail("Expected exception when attempting to create a user with a non ascii name");
}
catch(IllegalArgumentException e)
diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/sasl/CRAMMD5HexInitialiserTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/sasl/CRAMMD5HexInitialiserTest.java
index 3079222b1c..52bf6a39d7 100644
--- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/sasl/CRAMMD5HexInitialiserTest.java
+++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/sasl/CRAMMD5HexInitialiserTest.java
@@ -28,6 +28,7 @@ import java.security.NoSuchAlgorithmException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
+import javax.xml.bind.DatatypeConverter;
import junit.framework.TestCase;
@@ -35,7 +36,6 @@ import org.apache.qpid.server.security.auth.database.Base64MD5PasswordFilePrinci
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.
@@ -73,7 +73,13 @@ public class CRAMMD5HexInitialiserTest extends TestCase
public void setUp() throws Exception
{
super.setUp();
- _file = TestFileUtils.createTempFile(this, "password-file", new Passwd().getOutput(TEST_USER , TEST_PASSWORD));
+
+ MessageDigest md = MessageDigest.getInstance("MD5");
+
+ md.update(TEST_PASSWORD.getBytes("utf-8"));
+
+ _file = TestFileUtils.createTempFile(this, "password-file",
+ TEST_USER + ":" + DatatypeConverter.printBase64Binary(md.digest()));
}
public void tearDown() throws Exception
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js
index a439e0512a..8da0bafd06 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js
@@ -152,7 +152,8 @@ define(["dojo/_base/xhr",
util.isProviderManagingUsers = function(type)
{
- return (type === "PlainPasswordFile" || type === "Base64MD5PasswordFile" || type === "SCRAM-SHA-1" || type === "SCRAM-SHA-256");
+ return (type === "PlainPasswordFile" || type === "Base64MD5PasswordFile" || type === "SCRAM-SHA-1"
+ || type === "SCRAM-SHA-256" || type === "Plain" || type === "MD5" );
};
util.showSetAttributesDialog = function(attributeWidgetFactories, data, putURL, dialogTitle, category, type, appendNameToUrl)
diff --git a/qpid/java/broker/bin/qpid-passwd b/qpid/java/broker/bin/qpid-passwd
deleted file mode 100755
index 07b7db0cd3..0000000000
--- a/qpid/java/broker/bin/qpid-passwd
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/usr/bin/env bash
-#
-# 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.
-#
-
-if [ -z "$QPID_HOME" ]; then
- WHEREAMI=`dirname "$0"`
- export QPID_HOME=`cd "$WHEREAMI/../" && pwd`
-fi
-
-# Set classpath to include jars from lib dir
-QPID_LIBS=$QPID_HOME/lib/*
-
-# Set other variables used by the qpid-run script before calling
-export JAVA=java \
- JAVA_VM=-server \
- JAVA_MEM=-Xmx1024m \
- QPID_CLASSPATH=$QPID_LIBS
-
-. "${QPID_HOME}/bin/qpid-run" org.apache.qpid.tools.security.Passwd "$@"
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/scripts/QpidPasswdTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/scripts/QpidPasswdTest.java
deleted file mode 100644
index e483660f4c..0000000000
--- a/qpid/java/systests/src/test/java/org/apache/qpid/scripts/QpidPasswdTest.java
+++ /dev/null
@@ -1,80 +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.scripts;
-
-import java.io.File;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.qpid.test.utils.Piper;
-import org.apache.qpid.test.utils.QpidTestCase;
-import org.apache.qpid.util.SystemUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class QpidPasswdTest extends QpidTestCase
-{
- private static final Logger LOGGER = LoggerFactory.getLogger(QpidPasswdTest.class);
-
- private static final String PASSWD_SCRIPT = "qpid-passwd";
- private static final String EXPECTED_OUTPUT = "user1:rL0Y20zC+Fzt72VPzMSk2A==";
-
- public void testRunScript() throws Exception
- {
- if(SystemUtils.isWindows())
- {
- return;
- }
- Process process = null;
- try
- {
- String scriptPath =
- QpidTestCase.QPID_HOME + File.separatorChar
- + "bin" + File.separatorChar
- + PASSWD_SCRIPT;
-
- LOGGER.info("About to run script: " + scriptPath);
-
- ProcessBuilder pb = new ProcessBuilder(scriptPath, "user1", "foo");
- pb.redirectErrorStream(true);
- process = pb.start();
-
- Piper piper = new Piper(process.getInputStream(), System.out, EXPECTED_OUTPUT, EXPECTED_OUTPUT);
- piper.start();
-
- boolean finishedSuccessfully = piper.await(2, TimeUnit.SECONDS);
- assertTrue(
- "Script should have completed with expected output " + EXPECTED_OUTPUT + ". Check standard output for actual output.",
- finishedSuccessfully);
- process.waitFor();
- piper.join();
-
- assertEquals("Unexpected exit value from backup script", 0, process.exitValue());
- }
- finally
- {
- if (process != null)
- {
- process.getErrorStream().close();
- process.getInputStream().close();
- process.getOutputStream().close();
- }
- }
-
- }
-}
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementTest.java
index 25b09f04c3..0bcae6431c 100644
--- a/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementTest.java
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementTest.java
@@ -35,7 +35,6 @@ import org.apache.qpid.server.security.auth.manager.PlainPasswordDatabaseAuthent
import org.apache.qpid.test.utils.JMXTestUtils;
import org.apache.qpid.test.utils.QpidBrokerTestCase;
import org.apache.qpid.test.utils.TestBrokerConfiguration;
-import org.apache.qpid.tools.security.Passwd;
/**
* System test for User Management.
@@ -49,11 +48,9 @@ public class UserManagementTest extends QpidBrokerTestCase
private String _testUserName;
private File _passwordFile;
private UserManagement _userManagement;
- private Passwd _passwd;
public void setUp() throws Exception
{
- _passwd = createPasswordEncodingUtility();
_passwordFile = createTemporaryPasswordFileWithJmxAdminUser();
Map<String, Object> newAttributes = new HashMap<String, Object>();
@@ -161,17 +158,6 @@ public class UserManagementTest extends QpidBrokerTestCase
assertEquals("unexpected authentication provider type", getAuthenticationManagerType(), actualType);
}
- protected Passwd createPasswordEncodingUtility()
- {
- return new Passwd()
- {
- @Override
- public String getOutput(String username, String password)
- {
- return username + ":" + password;
- }
- };
- }
protected String getAuthenticationManagerType()
{
@@ -188,21 +174,25 @@ public class UserManagementTest extends QpidBrokerTestCase
private void writePasswordFile(File passwordFile, String... userNamePasswordPairs) throws Exception
{
- FileWriter writer = null;
- try
+ try(FileWriter writer = new FileWriter(passwordFile))
{
- writer = new FileWriter(passwordFile);
for (int i = 0; i < userNamePasswordPairs.length; i=i+2)
{
String username = userNamePasswordPairs[i];
String password = userNamePasswordPairs[i+1];
- writer.append(_passwd.getOutput(username, password) + "\n");
+ writeUsernamePassword(writer, username, password);
}
}
- finally
- {
- writer.close();
- }
+
+ }
+
+ protected void writeUsernamePassword(final FileWriter writer, final String username, final String password)
+ throws IOException
+ {
+ writer.append(username);
+ writer.append(':');
+ writer.append(password);
+ writer.append('\n');
}
@@ -218,10 +208,8 @@ public class UserManagementTest extends QpidBrokerTestCase
private boolean passwordFileContainsUser(String username) throws IOException
{
- BufferedReader reader = null;
- try
+ try(BufferedReader reader = new BufferedReader(new FileReader(_passwordFile)))
{
- reader = new BufferedReader(new FileReader(_passwordFile));
String line = reader.readLine();
while(line != null)
{
@@ -234,10 +222,6 @@ public class UserManagementTest extends QpidBrokerTestCase
return false;
}
- finally
- {
- reader.close();
- }
}
private void assertJmsConnectionSucceeds(String username, String password) throws Exception
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementWithBase64MD5PasswordsTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementWithBase64MD5PasswordsTest.java
index ff441169b3..96ee2d3ae6 100644
--- a/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementWithBase64MD5PasswordsTest.java
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementWithBase64MD5PasswordsTest.java
@@ -18,17 +18,42 @@
*/
package org.apache.qpid.systest.management.jmx;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+import javax.xml.bind.DatatypeConverter;
+
import org.apache.qpid.server.security.auth.manager.Base64MD5PasswordDatabaseAuthenticationManager;
-import org.apache.qpid.tools.security.Passwd;
+import org.apache.qpid.server.util.ServerScopedRuntimeException;
public class UserManagementWithBase64MD5PasswordsTest extends UserManagementTest
{
@Override
- protected Passwd createPasswordEncodingUtility()
+ protected void writeUsernamePassword(final FileWriter writer, final String username, final String password)
+ throws IOException
{
- return new Passwd();
+ writer.append(username);
+ writer.append(":");
+ byte[] data = password.getBytes(StandardCharsets.UTF_8);
+ MessageDigest md = null;
+ try
+ {
+ md = MessageDigest.getInstance("MD5");
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new ServerScopedRuntimeException("MD5 not supported although Java compliance requires it");
+ }
+
+ md.update(data);
+ writer.append(DatatypeConverter.printBase64Binary(md.digest()));
+ writer.append('\n');
}
+
@Override
protected String getAuthenticationManagerType()
{
diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/SaslRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/SaslRestTest.java
index 547b7b1b00..57a958edd0 100644
--- a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/SaslRestTest.java
+++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/SaslRestTest.java
@@ -29,11 +29,14 @@ import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
+import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import javax.xml.bind.DatatypeConverter;
+
import org.apache.commons.codec.binary.Base64;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;
@@ -41,7 +44,6 @@ import org.codehaus.jackson.map.JsonMappingException;
import org.apache.qpid.server.model.AuthenticationProvider;
import org.apache.qpid.server.security.auth.manager.Base64MD5PasswordDatabaseAuthenticationManager;
import org.apache.qpid.test.utils.TestBrokerConfiguration;
-import org.apache.qpid.tools.security.Passwd;
public class SaslRestTest extends QpidRestTestCase
{
@@ -353,7 +355,12 @@ public class SaslRestTest extends QpidRestTestCase
String passwordFileEntry;
try
{
- passwordFileEntry = new Passwd().getOutput("admin", "admin");
+
+ MessageDigest md = MessageDigest.getInstance("MD5");
+
+ md.update("admin".getBytes("utf-8"));
+
+ passwordFileEntry = "admin" + ":" + DatatypeConverter.printBase64Binary(md.digest());
}
catch (NoSuchAlgorithmException e)
{