diff options
| author | Robert Godfrey <rgodfrey@apache.org> | 2014-10-17 13:51:10 +0000 |
|---|---|---|
| committer | Robert Godfrey <rgodfrey@apache.org> | 2014-10-17 13:51:10 +0000 |
| commit | 152b079dacea71ccd5efe7ef0458836d8aea8d2f (patch) | |
| tree | cf0c33645ac33415488c710adeaf0a53454ae4d1 /qpid/java | |
| parent | ba126ca5218e76bd38be239aed9200cb33c66c99 (diff) | |
| download | qpid-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')
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) { |
