diff options
Diffstat (limited to 'qpid/java/broker/src/main/java/org/apache/qpid/server/security')
44 files changed, 803 insertions, 1359 deletions
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractPlugin.java index ff80499bc2..704e50da5c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractPlugin.java @@ -20,8 +20,8 @@ */ package org.apache.qpid.server.security; -import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.Logger; + import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; import org.apache.qpid.server.security.access.ObjectProperties; import org.apache.qpid.server.security.access.ObjectType; @@ -32,9 +32,9 @@ import org.apache.qpid.server.security.access.Operation; */ public abstract class AbstractPlugin implements SecurityPlugin { - protected final Logger _logger = Logger.getLogger(getClass()); + private final Logger _logger = Logger.getLogger(getClass()); - protected ConfigurationPlugin _config; + private ConfigurationPlugin _config; public Result getDefault() { @@ -50,4 +50,8 @@ public abstract class AbstractPlugin implements SecurityPlugin _config = config; } + public ConfigurationPlugin getConfig() + { + return _config; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java index ec11e2d39c..236931e8cd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AbstractProxyPlugin.java @@ -20,7 +20,6 @@ */ package org.apache.qpid.server.security; -import org.apache.commons.configuration.Configuration; import org.apache.qpid.server.security.access.ObjectProperties; import org.apache.qpid.server.security.access.ObjectType; import org.apache.qpid.server.security.access.Operation; @@ -28,8 +27,6 @@ import org.apache.qpid.server.security.access.Operation; /** * This {@link SecurityPlugin} proxies the authorise calls to a serries of methods, one per {@link Operation}. * - * Plugins that extend this class should override the relevant authorise method and implement their own - * {@link #setConfiguration(Configuration)} method. */ public abstract class AbstractProxyPlugin extends AbstractPlugin { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AuthorizationHolder.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AuthorizationHolder.java index 3d8c77a86f..8f3bdf7738 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AuthorizationHolder.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AuthorizationHolder.java @@ -20,12 +20,8 @@ */ package org.apache.qpid.server.security; -import java.security.Principal; - import javax.security.auth.Subject; - -import org.apache.qpid.server.security.auth.sasl.GroupPrincipal; -import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; +import java.security.Principal; /** * Represents the authorization of the logged on user. @@ -35,8 +31,8 @@ public interface AuthorizationHolder { /** * Returns the {@link Subject} of the authorized user. This is guaranteed to - * contain at least one {@link UsernamePrincipal}, representing the the identity - * used when the user logged on to the application, and zero or more {@link GroupPrincipal} + * contain at least one {@link org.apache.qpid.server.security.auth.sasl.UsernamePrincipal}, representing the the identity + * used when the user logged on to the application, and zero or more {@link org.apache.qpid.server.security.auth.sasl.GroupPrincipal} * representing the group(s) to which the user belongs. * * @return the Subject diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java index 2a1ae8a870..436660cfaf 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java @@ -18,6 +18,19 @@ */ package org.apache.qpid.server.security; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.log4j.Logger; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; +import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; +import org.apache.qpid.server.exchange.Exchange; +import org.apache.qpid.server.plugins.PluginManager; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.security.access.ObjectProperties; +import org.apache.qpid.server.security.access.Operation; + import static org.apache.qpid.server.security.access.ObjectType.EXCHANGE; import static org.apache.qpid.server.security.access.ObjectType.METHOD; import static org.apache.qpid.server.security.access.ObjectType.QUEUE; @@ -30,26 +43,17 @@ import static org.apache.qpid.server.security.access.Operation.PUBLISH; import static org.apache.qpid.server.security.access.Operation.PURGE; import static org.apache.qpid.server.security.access.Operation.UNBIND; +import javax.security.auth.Subject; import java.net.SocketAddress; -import java.security.Principal; -import java.util.*; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; -import javax.security.auth.Subject; - -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.log4j.Logger; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; -import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.plugins.PluginManager; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.security.access.ObjectProperties; -import org.apache.qpid.server.security.access.Operation; - /** * The security manager contains references to all loaded {@link SecurityPlugin}s and delegates security decisions to them based * on virtual host name. The plugins can be external <em>OSGi</em> .jar files that export the required classes or just internal @@ -61,7 +65,7 @@ public class SecurityManager { private static final Logger _logger = Logger.getLogger(SecurityManager.class); - /** Container for the {@link Principal} that is using to this thread. */ + /** Container for the {@link java.security.Principal} that is using to this thread. */ private static final ThreadLocal<Subject> _subject = new ThreadLocal<Subject>(); private static final ThreadLocal<Boolean> _accessChecksDisabled = new ThreadLocal<Boolean>() { @@ -101,7 +105,7 @@ public class SecurityManager public void validateConfiguration() throws ConfigurationException { - if (_configuration.isEmpty()) + if (getConfig().isEmpty()) { throw new ConfigurationException("security section is incomplete, no elements found."); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginActivator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginActivator.java index 5ee7833c4c..21c2d1cda5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginActivator.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityPluginActivator.java @@ -21,10 +21,11 @@ package org.apache.qpid.server.security; import org.apache.log4j.Logger; -import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; +import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; + /** * An OSGi {@link BundleActivator} that loads a {@link SecurityPluginFactory}. */ diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectProperties.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectProperties.java index 8a52d31f97..a9ec4d1647 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectProperties.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectProperties.java @@ -18,13 +18,17 @@ */ package org.apache.qpid.server.security.access; -import java.util.*; - import org.apache.commons.lang.StringUtils; + import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.queue.AMQQueue; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; + /** * An set of properties for an access control v2 rule {@link ObjectType}. * @@ -315,19 +319,28 @@ public class ObjectProperties || ruleValue.equals(STAR) || (ruleValue.endsWith(STAR) && thisValue != null - && thisValue.length() > ruleValue.length() - && thisValue.startsWith(ruleValue.substring(0, ruleValue.length() - 2))); + && thisValue.length() >= ruleValue.length() - 1 + && thisValue.startsWith(ruleValue.substring(0, ruleValue.length() - 1))); } @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) + { + return true; + } + if (o == null || getClass() != o.getClass()) + { + return false; + } ObjectProperties that = (ObjectProperties) o; - if (_properties != null ? !_properties.equals(that._properties) : that._properties != null) return false; + if (_properties != null ? !_properties.equals(that._properties) : that._properties != null) + { + return false; + } return true; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java index 69c7ff185a..90ecd1dd17 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java @@ -18,7 +18,15 @@ */ package org.apache.qpid.server.security.access; -import static org.apache.qpid.server.security.access.Operation.*; +import static org.apache.qpid.server.security.access.Operation.ACCESS; +import static org.apache.qpid.server.security.access.Operation.BIND; +import static org.apache.qpid.server.security.access.Operation.CONSUME; +import static org.apache.qpid.server.security.access.Operation.CREATE; +import static org.apache.qpid.server.security.access.Operation.DELETE; +import static org.apache.qpid.server.security.access.Operation.PUBLISH; +import static org.apache.qpid.server.security.access.Operation.PURGE; +import static org.apache.qpid.server.security.access.Operation.UNBIND; +import static org.apache.qpid.server.security.access.Operation.UPDATE; import java.util.EnumSet; import java.util.Set; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java deleted file mode 100644 index db18a89231..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/AllowAll.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.security.access.plugins; - -import java.util.Arrays; -import java.util.List; - -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; -import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; -import org.apache.qpid.server.security.Result; -import org.apache.qpid.server.security.SecurityPluginFactory; - -/** Always allow. */ -public class AllowAll extends BasicPlugin -{ - public static class AllowAllConfiguration extends ConfigurationPlugin { - public static final ConfigurationPluginFactory FACTORY = new ConfigurationPluginFactory() - { - public List<String> getParentPaths() - { - return Arrays.asList("security.allow-all", "virtualhosts.virtualhost.security.allow-all"); - } - - public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException - { - ConfigurationPlugin instance = new AllowAllConfiguration(); - instance.setConfiguration(path, config); - return instance; - } - }; - - public String[] getElementsProcessed() - { - return new String[] { "" }; - } - - public void validateConfiguration() throws ConfigurationException - { -// if (!_configuration.isEmpty()) -// { -// throw new ConfigurationException("allow-all section takes no elements."); -// } - } - - } - - public static final SecurityPluginFactory<AllowAll> FACTORY = new SecurityPluginFactory<AllowAll>() - { - public AllowAll newInstance(ConfigurationPlugin config) throws ConfigurationException - { - AllowAllConfiguration configuration = config.getConfiguration(AllowAllConfiguration.class.getName()); - - // If there is no configuration for this plugin then don't load it. - if (configuration == null) - { - return null; - } - - AllowAll plugin = new AllowAll(); - plugin.configure(configuration); - return plugin; - } - - public String getPluginName() - { - return AllowAll.class.getName(); - } - - public Class<AllowAll> getPluginClass() - { - return AllowAll.class; - } - }; - - @Override - public Result getDefault() - { - return Result.ALLOWED; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicPlugin.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicPlugin.java index f3161551dc..4df135a4ca 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicPlugin.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/BasicPlugin.java @@ -20,16 +20,14 @@ */ package org.apache.qpid.server.security.access.plugins; -import org.apache.commons.configuration.ConfigurationException; import org.apache.qpid.server.security.AbstractPlugin; import org.apache.qpid.server.security.Result; -import org.apache.qpid.server.security.SecurityPlugin; import org.apache.qpid.server.security.access.ObjectProperties; import org.apache.qpid.server.security.access.ObjectType; import org.apache.qpid.server.security.access.Operation; /** - * This {@link SecurityPlugin} simply abstains from all authorisation requests and ignores configuration. + * This {@link org.apache.qpid.server.security.SecurityPlugin} simply abstains from all authorisation requests and ignores configuration. */ public abstract class BasicPlugin extends AbstractPlugin { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java deleted file mode 100644 index 6c0fb1eaa4..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/DenyAll.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.security.access.plugins; - -import java.util.Arrays; -import java.util.List; - -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; -import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; -import org.apache.qpid.server.security.Result; -import org.apache.qpid.server.security.SecurityPluginFactory; - -/** Always Deny. */ -public class DenyAll extends BasicPlugin -{ - public static class DenyAllConfiguration extends ConfigurationPlugin { - public static final ConfigurationPluginFactory FACTORY = new ConfigurationPluginFactory() - { - public List<String> getParentPaths() - { - return Arrays.asList("security.deny-all", "virtualhosts.virtualhost.security.deny-all"); - } - - public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException - { - ConfigurationPlugin instance = new DenyAllConfiguration(); - instance.setConfiguration(path, config); - return instance; - } - }; - - public String[] getElementsProcessed() - { - return new String[] { "" }; - } - - public void validateConfiguration() throws ConfigurationException - { - if (!_configuration.isEmpty()) - { - throw new ConfigurationException("deny-all section takes no elements."); - } - } - - } - - public static final SecurityPluginFactory<DenyAll> FACTORY = new SecurityPluginFactory<DenyAll>() - { - public DenyAll newInstance(ConfigurationPlugin config) throws ConfigurationException - { - DenyAllConfiguration configuration = config.getConfiguration(DenyAllConfiguration.class.getName()); - - // If there is no configuration for this plugin then don't load it. - if (configuration == null) - { - return null; - } - - DenyAll plugin = new DenyAll(); - plugin.configure(configuration); - return plugin; - } - - public String getPluginName() - { - return DenyAll.class.getName(); - } - - public Class<DenyAll> getPluginClass() - { - return DenyAll.class; - } - }; - - @Override - public Result getDefault() - { - return Result.DENIED; - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccess.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccess.java index bd99cdd1fa..4b7a2fb457 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccess.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/plugins/LegacyAccess.java @@ -18,18 +18,19 @@ */ package org.apache.qpid.server.security.access.plugins; -import java.util.Arrays; -import java.util.List; - import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; + import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.qpid.server.configuration.ServerConfiguration; import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; import org.apache.qpid.server.security.SecurityPluginFactory; -/** Always Abstain. */ +import java.util.Arrays; +import java.util.List; + +/** + * The <code>LegacyAccess</code> plugin is used internally and simply ignores legacy elements of the configuration file. + */ public class LegacyAccess extends BasicPlugin { public static class LegacyAccessConfiguration extends ConfigurationPlugin { @@ -37,9 +38,7 @@ public class LegacyAccess extends BasicPlugin { public List<String> getParentPaths() { - return Arrays.asList("security.jmx", "virtualhosts.virtualhost.security.jmx", - "security.msg-auth", "virtualhosts.virtualhost.security.msg-auth", - "security.principal-databases", "virtualhosts.virtualhost.security.principal-databases"); + return Arrays.asList("security.msg-auth", "virtualhosts.virtualhost.security.msg-auth"); } public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java index 8c2d60a660..949c0f2b89 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java @@ -53,8 +53,8 @@ public class AuthenticationResult ERROR } - public final AuthenticationStatus _status; - public final byte[] _challenge; + private final AuthenticationStatus _status; + private final byte[] _challenge; private final Exception _cause; private final Subject _subject; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/AbstractPasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/AbstractPasswordFilePrincipalDatabase.java new file mode 100644 index 0000000000..7088fae50c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/AbstractPasswordFilePrincipalDatabase.java @@ -0,0 +1,484 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.database; + +import org.apache.log4j.Logger; +import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; +import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; + +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.login.AccountNotFoundException; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.io.PrintStream; +import java.security.Principal; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.concurrent.locks.ReentrantLock; +import java.util.regex.Pattern; + +public abstract class AbstractPasswordFilePrincipalDatabase<U extends PasswordPrincipal> implements PrincipalDatabase +{ + private final Pattern _regexp = Pattern.compile(":"); + + private final Map<String, AuthenticationProviderInitialiser> _saslServers = + new HashMap<String, AuthenticationProviderInitialiser>(); + + protected static final String DEFAULT_ENCODING = "utf-8"; + private final Map<String, U> _userMap = new HashMap<String, U>(); + private final ReentrantLock _userUpdate = new ReentrantLock(); + private final Random _random = new Random(); + private File _passwordFile; + + + protected AbstractPasswordFilePrincipalDatabase(UsernamePasswordInitialiser... initialisers) + { + for(UsernamePasswordInitialiser initialiser : initialisers) + { + initialiser.initialise(this); + _saslServers.put(initialiser.getMechanismName(), initialiser); + } + } + + public final void setPasswordFile(String passwordFile) throws IOException + { + File f = new File(passwordFile); + getLogger().info("PasswordFile using file " + f.getAbsolutePath()); + _passwordFile = f; + if (!f.exists()) + { + throw new FileNotFoundException("Cannot find password file " + f); + } + if (!f.canRead()) + { + throw new FileNotFoundException("Cannot read password file " + f + + ". Check permissions."); + } + + loadPasswordFile(); + } + + /** + * SASL Callback Mechanism - sets the Password in the PasswordCallback based on the value in the PasswordFile + * If you want to change the password for a user, use updatePassword instead. + * + * @param principal The Principal to set the password for + * @param callback The PasswordCallback to call setPassword on + * + * @throws javax.security.auth.login.AccountNotFoundException If the Principal cannot be found in this Database + */ + public final void setPassword(Principal principal, PasswordCallback callback) throws AccountNotFoundException + { + if (_passwordFile == null) + { + throw new AccountNotFoundException("Unable to locate principal since no password file was specified during initialisation"); + } + if (principal == null) + { + throw new IllegalArgumentException("principal must not be null"); + } + char[] pwd = lookupPassword(principal.getName()); + + if (pwd != null) + { + callback.setPassword(pwd); + } + else + { + throw new AccountNotFoundException("No account found for principal " + principal); + } + } + + + /** + * Looks up the password for a specified user in the password file. Note this code is <b>not</b> secure since it + * creates strings of passwords. It should be modified to create only char arrays which get nulled out. + * + * @param name The principal name to lookup + * + * @return a char[] for use in SASL. + */ + protected final char[] lookupPassword(String name) + { + U user = _userMap.get(name); + if (user == null) + { + return null; + } + else + { + return user.getPassword(); + } + } + + protected boolean compareCharArray(char[] a, char[] b) + { + boolean equal = false; + if (a.length == b.length) + { + equal = true; + int index = 0; + while (equal && index < a.length) + { + equal = a[index] == b[index]; + index++; + } + } + return equal; + } + + /** + * Changes the password for the specified user + * + * @param principal to change the password for + * @param password plaintext password to set the password too + */ + public boolean updatePassword(Principal principal, char[] password) throws AccountNotFoundException + { + U user = _userMap.get(principal.getName()); + + if (user == null) + { + throw new AccountNotFoundException(principal.getName()); + } + + char[] orig = user.getPassword(); + _userUpdate.lock(); + try + { + user.setPassword(password); + + savePasswordFile(); + + return true; + } + catch (IOException e) + { + getLogger().error("Unable to save password file due to '" + e.getMessage() + + "', password change for user '" + principal + "' discarded"); + //revert the password change + user.restorePassword(orig); + + return false; + } + finally + { + _userUpdate.unlock(); + } + } + + + private void loadPasswordFile() throws IOException + { + try + { + _userUpdate.lock(); + _userMap.clear(); + + BufferedReader reader = null; + try + { + reader = new BufferedReader(new FileReader(_passwordFile)); + String line; + + while ((line = reader.readLine()) != null) + { + String[] result = _regexp.split(line); + if (result == null || result.length < 2 || result[0].startsWith("#")) + { + continue; + } + + U user = createUserFromFileData(result); + getLogger().info("Created user:" + user); + _userMap.put(user.getName(), user); + } + } + finally + { + if (reader != null) + { + reader.close(); + } + } + } + finally + { + _userUpdate.unlock(); + } + } + + protected abstract U createUserFromFileData(String[] result); + + + protected abstract Logger getLogger(); + + protected File createTempFileOnSameFilesystem() + { + File liveFile = _passwordFile; + File tmp; + + do + { + tmp = new File(liveFile.getPath() + _random.nextInt() + ".tmp"); + } + while(tmp.exists()); + + tmp.deleteOnExit(); + return tmp; + } + + protected void swapTempFileToLive(final File temp) throws IOException + { + File live = _passwordFile; + // Remove any existing ".old" file + final File old = new File(live.getAbsoluteFile() + ".old"); + if (old.exists()) + { + old.delete(); + } + + // Create an new ".old" file + if(!live.renameTo(old)) + { + //unable to rename the existing file to the backup name + getLogger().error("Could not backup the existing password file"); + throw new IOException("Could not backup the existing password file"); + } + + // Move temp file to be the new "live" file + if(!temp.renameTo(live)) + { + //failed to rename the new file to the required filename + if(!old.renameTo(live)) + { + //unable to return the backup to required filename + getLogger().error( + "Could not rename the new password file into place, and unable to restore original file"); + throw new IOException("Could not rename the new password file into place, and unable to restore original file"); + } + + getLogger().error("Could not rename the new password file into place"); + throw new IOException("Could not rename the new password file into place"); + } + } + + protected void savePasswordFile() throws IOException + { + try + { + _userUpdate.lock(); + + BufferedReader reader = null; + PrintStream writer = null; + + File tmp = createTempFileOnSameFilesystem(); + + try + { + writer = new PrintStream(tmp); + reader = new BufferedReader(new FileReader(_passwordFile)); + String line; + + while ((line = reader.readLine()) != null) + { + String[] result = _regexp.split(line); + if (result == null || result.length < 2 || result[0].startsWith("#")) + { + writer.write(line.getBytes(DEFAULT_ENCODING)); + writer.println(); + continue; + } + + U user = _userMap.get(result[0]); + + if (user == null) + { + writer.write(line.getBytes(DEFAULT_ENCODING)); + writer.println(); + } + else if (!user.isDeleted()) + { + if (!user.isModified()) + { + writer.write(line.getBytes(DEFAULT_ENCODING)); + writer.println(); + } + else + { + byte[] encodedPassword = user.getEncodedPassword(); + + writer.write((user.getName() + ":").getBytes(DEFAULT_ENCODING)); + writer.write(encodedPassword); + writer.println(); + + user.saved(); + } + } + } + + for (U user : _userMap.values()) + { + if (user.isModified()) + { + byte[] encodedPassword; + encodedPassword = user.getEncodedPassword(); + writer.write((user.getName() + ":").getBytes(DEFAULT_ENCODING)); + writer.write(encodedPassword); + writer.println(); + user.saved(); + } + } + } + catch(IOException e) + { + getLogger().error("Unable to create the new password file: " + e); + throw new IOException("Unable to create the new password file",e); + } + finally + { + + try + { + if (reader != null) + { + reader.close(); + } + } + finally + { + if (writer != null) + { + writer.close(); + } + } + + } + + swapTempFileToLive(tmp); + } + finally + { + _userUpdate.unlock(); + } + } + + protected abstract U createUserFromPassword(Principal principal, char[] passwd); + + + public void reload() throws IOException + { + loadPasswordFile(); + } + + public Map<String, AuthenticationProviderInitialiser> getMechanisms() + { + return _saslServers; + } + + public List<Principal> getUsers() + { + return new LinkedList<Principal>(_userMap.values()); + } + + public Principal getUser(String username) + { + if (_userMap.containsKey(username)) + { + return new UsernamePrincipal(username); + } + return null; + } + + public boolean deletePrincipal(Principal principal) throws AccountNotFoundException + { + U user = _userMap.get(principal.getName()); + + if (user == null) + { + throw new AccountNotFoundException(principal.getName()); + } + + try + { + _userUpdate.lock(); + user.delete(); + + try + { + savePasswordFile(); + } + catch (IOException e) + { + getLogger().error("Unable to remove user '" + user.getName() + "' from password file."); + return false; + } + + _userMap.remove(user.getName()); + } + finally + { + _userUpdate.unlock(); + } + + return true; + } + + public boolean createPrincipal(Principal principal, char[] password) + { + if (_userMap.get(principal.getName()) != null) + { + return false; + } + + U user = createUserFromPassword(principal, password); + + + try + { + _userUpdate.lock(); + _userMap.put(user.getName(), user); + + try + { + savePasswordFile(); + return true; + } + catch (IOException e) + { + //remove the use on failure. + _userMap.remove(user.getName()); + return false; + } + } + finally + { + _userUpdate.unlock(); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java index 5a92b33e43..63eb768035 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java @@ -21,29 +21,12 @@ package org.apache.qpid.server.security.auth.database; import org.apache.log4j.Logger; -import org.apache.qpid.server.security.auth.management.AMQUserManagementMBean; -import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; -import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; -import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HexInitialiser; + import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HashedInitialiser; -import org.apache.qpid.util.FileUtils; +import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HexInitialiser; -import javax.security.auth.callback.PasswordCallback; import javax.security.auth.login.AccountNotFoundException; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; -import java.io.PrintStream; import java.security.Principal; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.concurrent.locks.ReentrantLock; -import java.util.regex.Pattern; /** * Represents a user database where the account information is stored in a simple flat file. @@ -52,100 +35,19 @@ import java.util.regex.Pattern; * * where a carriage return separates each username/password pair. Passwords are assumed to be in plain text. */ -public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase +public class Base64MD5PasswordFilePrincipalDatabase extends AbstractPasswordFilePrincipalDatabase<HashedUser> { - private static final Logger _logger = Logger.getLogger(Base64MD5PasswordFilePrincipalDatabase.class); - - private File _passwordFile; - - private Pattern _regexp = Pattern.compile(":"); - - private Map<String, AuthenticationProviderInitialiser> _saslServers; - - AMQUserManagementMBean _mbean; - public static final String DEFAULT_ENCODING = "utf-8"; - private Map<String, HashedUser> _users = new HashMap<String, HashedUser>(); - private ReentrantLock _userUpdate = new ReentrantLock(); + private final Logger _logger = Logger.getLogger(Base64MD5PasswordFilePrincipalDatabase.class); public Base64MD5PasswordFilePrincipalDatabase() { - _saslServers = new HashMap<String, AuthenticationProviderInitialiser>(); - /** * Create Authenticators for MD5 Password file. */ + super(new CRAMMD5HashedInitialiser(), new CRAMMD5HexInitialiser()); - // Accept Plain incomming and hash it for comparison to the file. - CRAMMD5HashedInitialiser cram = new CRAMMD5HashedInitialiser(); - cram.initialise(this); - _saslServers.put(cram.getMechanismName(), cram); - - //Add the Hex initialiser - CRAMMD5HexInitialiser cramHex = new CRAMMD5HexInitialiser(); - cramHex.initialise(this); - _saslServers.put(cramHex.getMechanismName(), cramHex); - - //fixme The PDs should setup a PD Mangement MBean -// try -// { -// _mbean = new AMQUserManagementMBean(); -// _mbean.setPrincipalDatabase(this); -// } -// catch (JMException e) -// { -// _logger.warn("User management disabled as unable to create MBean:" + e); -// } - } - - public void setPasswordFile(String passwordFile) throws IOException - { - File f = new File(passwordFile); - _logger.info("PasswordFilePrincipalDatabase using file " + f.getAbsolutePath()); - _passwordFile = f; - if (!f.exists()) - { - throw new FileNotFoundException("Cannot find password file " + f); - } - if (!f.canRead()) - { - throw new FileNotFoundException("Cannot read password file " + f + - ". Check permissions."); - } - - loadPasswordFile(); } - /** - * SASL Callback Mechanism - sets the Password in the PasswordCallback based on the value in the PasswordFile - * If you want to change the password for a user, use updatePassword instead. - * - * @param principal The Principal to set the password for - * @param callback The PasswordCallback to call setPassword on - * - * @throws AccountNotFoundException If the Principal cannont be found in this Database - */ - public void setPassword(Principal principal, PasswordCallback callback) throws AccountNotFoundException - { - if (_passwordFile == null) - { - throw new AccountNotFoundException("Unable to locate principal since no password file was specified during initialisation"); - } - if (principal == null) - { - throw new IllegalArgumentException("principal must not be null"); - } - - char[] pwd = lookupPassword(principal.getName()); - - if (pwd != null) - { - callback.setPassword(pwd); - } - else - { - throw new AccountNotFoundException("No account found for principal " + principal); - } - } /** * Used to verify that the presented Password is correct. Currently only used by Management Console @@ -180,7 +82,7 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase } catch (Exception e1) { - _logger.warn("Unable to hash password for user '" + principal + "' for comparison"); + getLogger().warn("Unable to hash password for user '" + principal + "' for comparison"); return false; } @@ -194,374 +96,21 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase return compareCharArray(pwd, hashedPassword); } - - private boolean compareCharArray(char[] a, char[] b) - { - boolean equal = false; - if (a.length == b.length) - { - equal = true; - int index = 0; - while (equal && index < a.length) - { - equal = a[index] == b[index]; - index++; - } - } - return equal; - } - /** - * Changes the password for the specified user - * - * @param principal to change the password for - * @param password plaintext password to set the password too - */ - public boolean updatePassword(Principal principal, char[] password) throws AccountNotFoundException + protected HashedUser createUserFromPassword(Principal principal, char[] passwd) { - HashedUser user = _users.get(principal.getName()); - - if (user == null) - { - throw new AccountNotFoundException(principal.getName()); - } - - try - { - try - { - _userUpdate.lock(); - char[] orig = user.getPassword(); - user.setPassword(password,false); - - try - { - savePasswordFile(); - } - catch (IOException e) - { - _logger.error("Unable to save password file, password change for user'" - + principal + "' will revert at restart"); - //revert the password change - user.setPassword(orig,true); - return false; - } - return true; - } - finally - { - _userUpdate.unlock(); - } - } - catch (Exception e) - { - return false; - } + return new HashedUser(principal.getName(), passwd); } - public boolean createPrincipal(Principal principal, char[] password) - { - if (_users.get(principal.getName()) != null) - { - return false; - } - HashedUser user; - try - { - user = new HashedUser(principal.getName(), password); - } - catch (Exception e1) - { - _logger.warn("Unable to create new user '" + principal.getName() + "'"); - return false; - } - - - try - { - _userUpdate.lock(); - _users.put(user.getName(), user); - - try - { - savePasswordFile(); - return true; - } - catch (IOException e) - { - //remove the use on failure. - _users.remove(user.getName()); - return false; - } - } - finally - { - _userUpdate.unlock(); - } - } - - public boolean deletePrincipal(Principal principal) throws AccountNotFoundException - { - HashedUser user = _users.get(principal.getName()); - - if (user == null) - { - throw new AccountNotFoundException(principal.getName()); - } - - try - { - _userUpdate.lock(); - user.delete(); - - try - { - savePasswordFile(); - } - catch (IOException e) - { - _logger.warn("Unable to remove user '" + user.getName() + "' from password file."); - return false; - } - - _users.remove(user.getName()); - } - finally - { - _userUpdate.unlock(); - } - - return true; - } - - public Map<String, AuthenticationProviderInitialiser> getMechanisms() - { - return _saslServers; - } - - public List<Principal> getUsers() - { - return new LinkedList<Principal>(_users.values()); - } - - public Principal getUser(String username) - { - if (_users.containsKey(username)) - { - return new UsernamePrincipal(username); - } - return null; - } - - /** - * Looks up the password for a specified user in the password file. Note this code is <b>not</b> secure since it - * creates strings of passwords. It should be modified to create only char arrays which get nulled out. - * - * @param name The principal name to lookup - * - * @return a char[] for use in SASL. - */ - private char[] lookupPassword(String name) + protected HashedUser createUserFromFileData(String[] result) { - HashedUser user = _users.get(name); - if (user == null) - { - return null; - } - else - { - return user.getPassword(); - } - } - - private void loadPasswordFile() throws IOException - { - try - { - _userUpdate.lock(); - _users.clear(); - - BufferedReader reader = null; - try - { - reader = new BufferedReader(new FileReader(_passwordFile)); - String line; - - while ((line = reader.readLine()) != null) - { - String[] result = _regexp.split(line); - if (result == null || result.length < 2 || result[0].startsWith("#")) - { - continue; - } - - HashedUser user = new HashedUser(result); - _logger.info("Created user:" + user); - _users.put(user.getName(), user); - } - } - finally - { - if (reader != null) - { - reader.close(); - } - } - } - finally - { - _userUpdate.unlock(); - } - } - - private void savePasswordFile() throws IOException - { - try - { - _userUpdate.lock(); - - BufferedReader reader = null; - PrintStream writer = null; - - Random r = new Random(); - File tmp; - do - { - tmp = new File(_passwordFile.getPath() + r.nextInt() + ".tmp"); - } - while(tmp.exists()); - - tmp.deleteOnExit(); - - try - { - writer = new PrintStream(tmp); - reader = new BufferedReader(new FileReader(_passwordFile)); - String line; - - while ((line = reader.readLine()) != null) - { - String[] result = _regexp.split(line); - if (result == null || result.length < 2 || result[0].startsWith("#")) - { - writer.write(line.getBytes(DEFAULT_ENCODING)); - writer.println(); - continue; - } - - HashedUser user = _users.get(result[0]); - - if (user == null) - { - writer.write(line.getBytes(DEFAULT_ENCODING)); - writer.println(); - } - else if (!user.isDeleted()) - { - if (!user.isModified()) - { - writer.write(line.getBytes(DEFAULT_ENCODING)); - writer.println(); - } - else - { - try - { - byte[] encodedPassword = user.getEncodedPassword(); - - writer.write((user.getName() + ":").getBytes(DEFAULT_ENCODING)); - writer.write(encodedPassword); - writer.println(); - - user.saved(); - } - catch (Exception e) - { - _logger.warn("Unable to encode new password reverting to old password."); - writer.write(line.getBytes(DEFAULT_ENCODING)); - writer.println(); - } - } - } - } - - for (HashedUser user : _users.values()) - { - if (user.isModified()) - { - byte[] encodedPassword; - try - { - encodedPassword = user.getEncodedPassword(); - writer.write((user.getName() + ":").getBytes(DEFAULT_ENCODING)); - writer.write(encodedPassword); - writer.println(); - user.saved(); - } - catch (Exception e) - { - _logger.warn("Unable to get Encoded password for user'" + user.getName() + "' password not saved"); - } - } - } - } - catch(IOException e) - { - _logger.error("Unable to create the new password file: " + e); - throw new IOException("Unable to create the new password file" + e); - } - finally - { - if (reader != null) - { - reader.close(); - } - - if (writer != null) - { - writer.close(); - } - } - - // Swap temp file to main password file. - File old = new File(_passwordFile.getAbsoluteFile() + ".old"); - if (old.exists()) - { - old.delete(); - } - - if(!_passwordFile.renameTo(old)) - { - //unable to rename the existing file to the backup name - _logger.error("Could not backup the existing password file"); - throw new IOException("Could not backup the existing password file"); - } - - if(!tmp.renameTo(_passwordFile)) - { - //failed to rename the new file to the required filename - - if(!old.renameTo(_passwordFile)) - { - //unable to return the backup to required filename - _logger.error("Could not rename the new password file into place, and unable to restore original file"); - throw new IOException("Could not rename the new password file into place, and unable to restore original file"); - } - - _logger.error("Could not rename the new password file into place"); - throw new IOException("Could not rename the new password file into place"); - } - } - finally - { - _userUpdate.unlock(); - } + return new HashedUser(result); } - public void reload() throws IOException + protected Logger getLogger() { - loadPasswordFile(); + return _logger; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java index 3690e7f92a..b9de1587b5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/HashedUser.java @@ -20,26 +20,25 @@ */ package org.apache.qpid.server.security.auth.database; -import org.apache.commons.codec.EncoderException; import org.apache.commons.codec.binary.Base64; import org.apache.log4j.Logger; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import java.security.Principal; -public class HashedUser implements Principal + +public class HashedUser implements PasswordPrincipal { private static final Logger _logger = Logger.getLogger(HashedUser.class); - String _name; - char[] _password; - byte[] _encodedPassword = null; + private String _name; + private char[] _password; + private byte[] _encodedPassword = null; private boolean _modified = false; private boolean _deleted = false; - HashedUser(String[] data) throws UnsupportedEncodingException + HashedUser(String[] data) { if (data.length != 2) { @@ -48,7 +47,15 @@ public class HashedUser implements Principal _name = data[0]; - byte[] encoded_password = data[1].getBytes(Base64MD5PasswordFilePrincipalDatabase.DEFAULT_ENCODING); + byte[] encoded_password; + try + { + encoded_password = data[1].getBytes(Base64MD5PasswordFilePrincipalDatabase.DEFAULT_ENCODING); + } + catch (UnsupportedEncodingException e) + { + throw new RuntimeException("MD5 encoding not supported, even though the Java standard requires it",e); + } Base64 b64 = new Base64(); byte[] decoded = b64.decode(encoded_password); @@ -64,15 +71,23 @@ public class HashedUser implements Principal } } - public HashedUser(String name, char[] password) throws UnsupportedEncodingException, NoSuchAlgorithmException + public HashedUser(String name, char[] password) { _name = name; setPassword(password,false); } - public static byte[] getMD5(byte[] data) throws NoSuchAlgorithmException, UnsupportedEncodingException + public static byte[] getMD5(byte[] data) { - MessageDigest md = MessageDigest.getInstance("MD5"); + MessageDigest md = null; + try + { + md = MessageDigest.getInstance("MD5"); + } + catch (NoSuchAlgorithmException e) + { + throw new RuntimeException("MD5 not supported although Java compliance requires it"); + } for (byte b : data) { @@ -92,12 +107,22 @@ public class HashedUser implements Principal return _name; } - char[] getPassword() + public char[] getPassword() { return _password; } - void setPassword(char[] password, boolean alreadyHashed) throws UnsupportedEncodingException, NoSuchAlgorithmException + public void setPassword(char[] password) + { + setPassword(password, false); + } + + public void restorePassword(char[] password) + { + setPassword(password, true); + } + + void setPassword(char[] password, boolean alreadyHashed) { if(alreadyHashed){ _password = password; @@ -126,7 +151,7 @@ public class HashedUser implements Principal _encodedPassword = null; } - byte[] getEncodedPassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException + public byte[] getEncodedPassword() { if (_encodedPassword == null) { @@ -135,7 +160,7 @@ public class HashedUser implements Principal return _encodedPassword; } - private void encodePassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException + private void encodePassword() { byte[] byteArray = new byte[_password.length]; int index = 0; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PasswordPrincipal.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PasswordPrincipal.java new file mode 100644 index 0000000000..8e12d5f0a3 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PasswordPrincipal.java @@ -0,0 +1,40 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.database; + +import java.security.Principal; + +interface PasswordPrincipal extends Principal +{ + char[] getPassword(); + byte[] getEncodedPassword(); + + void setPassword(char[] password); + void restorePassword(char[] password); + + boolean isDeleted(); + + boolean isModified(); + + void saved(); + + void delete(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java index 7cb34da804..bfd04adb3f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java @@ -21,29 +21,13 @@ package org.apache.qpid.server.security.auth.database; import org.apache.log4j.Logger; -import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; -import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; + import org.apache.qpid.server.security.auth.sasl.amqplain.AmqPlainInitialiser; -import org.apache.qpid.server.security.auth.sasl.anonymous.AnonymousInitialiser; import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5Initialiser; import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser; -import javax.security.auth.callback.PasswordCallback; import javax.security.auth.login.AccountNotFoundException; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; -import java.io.PrintStream; import java.security.Principal; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.concurrent.locks.ReentrantLock; -import java.util.regex.Pattern; /** * Represents a user database where the account information is stored in a simple flat file. @@ -52,102 +36,19 @@ import java.util.regex.Pattern; * * where a carriage return separates each username/password pair. Passwords are assumed to be in plain text. */ -public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase +public class PlainPasswordFilePrincipalDatabase extends AbstractPasswordFilePrincipalDatabase<PlainUser> { - public static final String DEFAULT_ENCODING = "utf-8"; - - private static final Logger _logger = Logger.getLogger(PlainPasswordFilePrincipalDatabase.class); - - private File _passwordFile; - - private Pattern _regexp = Pattern.compile(":"); - private Map<String, AuthenticationProviderInitialiser> _saslServers; - - private Map<String, PlainUser> _users = new HashMap<String, PlainUser>(); - private ReentrantLock _userUpdate = new ReentrantLock(); + private final Logger _logger = Logger.getLogger(PlainPasswordFilePrincipalDatabase.class); public PlainPasswordFilePrincipalDatabase() { - _saslServers = new HashMap<String, AuthenticationProviderInitialiser>(); - /** * Create Authenticators for Plain Password file. */ - - // Accept AMQPlain incomming and compare it to the file. - AmqPlainInitialiser amqplain = new AmqPlainInitialiser(); - amqplain.initialise(this); - - - - // Accept AMQPlain incomming and compare it to the file. - AnonymousInitialiser anonymous = new AnonymousInitialiser(); - anonymous.initialise(this); - - - // Accept Plain incomming and compare it to the file. - PlainInitialiser plain = new PlainInitialiser(); - plain.initialise(this); - - // Accept MD5 incomming and Hash file value for comparison - CRAMMD5Initialiser cram = new CRAMMD5Initialiser(); - cram.initialise(this); - - _saslServers.put(amqplain.getMechanismName(), amqplain); - _saslServers.put(plain.getMechanismName(), plain); - _saslServers.put(cram.getMechanismName(), cram); - _saslServers.put(anonymous.getMechanismName(), anonymous); - } - - public void setPasswordFile(String passwordFile) throws IOException - { - File f = new File(passwordFile); - _logger.info("PlainPasswordFile using file " + f.getAbsolutePath()); - _passwordFile = f; - if (!f.exists()) - { - throw new FileNotFoundException("Cannot find password file " + f); - } - if (!f.canRead()) - { - throw new FileNotFoundException("Cannot read password file " + f + - ". Check permissions."); - } - - loadPasswordFile(); + super(new AmqPlainInitialiser(), new PlainInitialiser(), new CRAMMD5Initialiser()); } - /** - * SASL Callback Mechanism - sets the Password in the PasswordCallback based on the value in the PasswordFile - * If you want to change the password for a user, use updatePassword instead. - * - * @param principal The Principal to set the password for - * @param callback The PasswordCallback to call setPassword on - * - * @throws AccountNotFoundException If the Principal cannot be found in this Database - */ - public void setPassword(Principal principal, PasswordCallback callback) throws AccountNotFoundException - { - if (_passwordFile == null) - { - throw new AccountNotFoundException("Unable to locate principal since no password file was specified during initialisation"); - } - if (principal == null) - { - throw new IllegalArgumentException("principal must not be null"); - } - char[] pwd = lookupPassword(principal.getName()); - - if (pwd != null) - { - callback.setPassword(pwd); - } - else - { - throw new AccountNotFoundException("No account found for principal " + principal); - } - } /** * Used to verify that the presented Password is correct. Currently only used by Management Console @@ -173,352 +74,21 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase } - /** - * Changes the password for the specified user - * - * @param principal to change the password for - * @param password plaintext password to set the password too - */ - public boolean updatePassword(Principal principal, char[] password) throws AccountNotFoundException + protected PlainUser createUserFromPassword(Principal principal, char[] passwd) { - PlainUser user = _users.get(principal.getName()); - - if (user == null) - { - throw new AccountNotFoundException(principal.getName()); - } - - char[] orig = user.getPassword(); - _userUpdate.lock(); - try - { - user.setPassword(password); - - savePasswordFile(); - - return true; - } - catch (IOException e) - { - _logger.error("Unable to save password file due to '"+e.getMessage() - +"', password change for user '" + principal + "' discarded"); - //revert the password change - user.setPassword(orig); - return false; - } - finally - { - _userUpdate.unlock(); - } + return new PlainUser(principal.getName(), passwd); } - public boolean createPrincipal(Principal principal, char[] password) - { - if (_users.get(principal.getName()) != null) - { - return false; - } - - PlainUser user = new PlainUser(principal.getName(), password); - - try - { - _userUpdate.lock(); - _users.put(user.getName(), user); - - try - { - savePasswordFile(); - return true; - } - catch (IOException e) - { - //remove the use on failure. - _users.remove(user.getName()); - _logger.warn("Unable to create user '" + user.getName()); - return false; - } - } - finally - { - _userUpdate.unlock(); - } - } - public boolean deletePrincipal(Principal principal) throws AccountNotFoundException + @Override + protected PlainUser createUserFromFileData(String[] result) { - PlainUser user = _users.get(principal.getName()); - - if (user == null) - { - throw new AccountNotFoundException(principal.getName()); - } - - try - { - _userUpdate.lock(); - user.delete(); - - try - { - savePasswordFile(); - } - catch (IOException e) - { - _logger.error("Unable to remove user '" + user.getName() + "' from password file."); - return false; - } - - _users.remove(user.getName()); - } - finally - { - _userUpdate.unlock(); - } - - return true; + return new PlainUser(result); } - public Map<String, AuthenticationProviderInitialiser> getMechanisms() - { - return _saslServers; - } - public List<Principal> getUsers() - { - return new LinkedList<Principal>(_users.values()); - } - - public Principal getUser(String username) - { - if (_users.containsKey(username)) - { - return new UsernamePrincipal(username); - } - return null; - } - - private boolean compareCharArray(char[] a, char[] b) - { - boolean equal = false; - if (a.length == b.length) - { - equal = true; - int index = 0; - while (equal && index < a.length) - { - equal = a[index] == b[index]; - index++; - } - } - return equal; - } - - - /** - * Looks up the password for a specified user in the password file. Note this code is <b>not</b> secure since it - * creates strings of passwords. It should be modified to create only char arrays which get nulled out. - * - * @param name The principal name to lookup - * - * @return a char[] for use in SASL. - */ - private char[] lookupPassword(String name) - { - PlainUser user = _users.get(name); - if (user == null) - { - return null; - } - else - { - return user.getPassword(); - } - } - - private void loadPasswordFile() throws IOException - { - try - { - _userUpdate.lock(); - _users.clear(); - - BufferedReader reader = null; - try - { - reader = new BufferedReader(new FileReader(_passwordFile)); - String line; - - while ((line = reader.readLine()) != null) - { - String[] result = _regexp.split(line); - if (result == null || result.length < 2 || result[0].startsWith("#")) - { - continue; - } - - PlainUser user = new PlainUser(result); - _logger.info("Created user:" + user); - _users.put(user.getName(), user); - } - } - finally - { - if (reader != null) - { - reader.close(); - } - } - } - finally - { - _userUpdate.unlock(); - } - } - - private void savePasswordFile() throws IOException - { - try - { - _userUpdate.lock(); - - BufferedReader reader = null; - PrintStream writer = null; - - final File tmp = createTempFileOnSameFilesystem(_passwordFile); - - try - { - writer = new PrintStream(tmp); - reader = new BufferedReader(new FileReader(_passwordFile)); - String line; - - while ((line = reader.readLine()) != null) - { - String[] result = _regexp.split(line); - if (result == null || result.length < 2 || result[0].startsWith("#")) - { - writer.write(line.getBytes(DEFAULT_ENCODING)); - writer.println(); - continue; - } - - PlainUser user = _users.get(result[0]); - - if (user == null) - { - writer.write(line.getBytes(DEFAULT_ENCODING)); - writer.println(); - } - else if (!user.isDeleted()) - { - if (!user.isModified()) - { - writer.write(line.getBytes(DEFAULT_ENCODING)); - writer.println(); - } - else - { - byte[] password = user.getPasswordBytes(); - - writer.write((user.getName() + ":").getBytes(DEFAULT_ENCODING)); - writer.write(password); - writer.println(); - - user.saved(); - } - } - } - - for (PlainUser user : _users.values()) - { - if (user.isModified()) - { - byte[] password; - password = user.getPasswordBytes(); - writer.write((user.getName() + ":").getBytes(DEFAULT_ENCODING)); - writer.write(password); - writer.println(); - user.saved(); - } - } - } - catch(IOException e) - { - _logger.error("Unable to create the new password file: " + e); - throw new IOException("Unable to create the new password file" + e); - } - finally - { - if (writer != null) - { - writer.close(); - } - if (reader != null) - { - reader.close(); - } - } - - swapTempFileToLive(_passwordFile, tmp); - - } - finally - { - _userUpdate.unlock(); - } - } - - private void swapTempFileToLive(final File live, final File temp) throws IOException - { - // Remove any existing ".old" file - final File old = new File(live.getAbsoluteFile() + ".old"); - if (old.exists()) - { - old.delete(); - } - - // Create an new ".old" file - if(!live.renameTo(old)) - { - //unable to rename the existing file to the backup name - _logger.error("Could not backup the existing password file"); - throw new IOException("Could not backup the existing password file"); - } - - // Move temp file to be the new "live" file - if(!temp.renameTo(live)) - { - //failed to rename the new file to the required filename - if(!old.renameTo(live)) - { - //unable to return the backup to required filename - _logger.error("Could not rename the new password file into place, and unable to restore original file"); - throw new IOException("Could not rename the new password file into place, and unable to restore original file"); - } - - _logger.error("Could not rename the new password file into place"); - throw new IOException("Could not rename the new password file into place"); - } - } - - private File createTempFileOnSameFilesystem(final File liveFile) - { - File tmp; - final Random r = new Random(); - - do - { - tmp = new File(liveFile.getPath() + r.nextInt() + ".tmp"); - } - while(tmp.exists()); - - tmp.deleteOnExit(); - return tmp; - } - - public void reload() throws IOException + protected Logger getLogger() { - loadPasswordFile(); + return _logger; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainUser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainUser.java index 46a78a55aa..bf9bfc6c99 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainUser.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainUser.java @@ -20,11 +20,7 @@ */ package org.apache.qpid.server.security.auth.database; -import org.apache.log4j.Logger; - -import java.security.Principal; - -public class PlainUser implements Principal +public class PlainUser implements PasswordPrincipal { private String _name; private char[] _password; @@ -61,12 +57,12 @@ public class PlainUser implements Principal return _name; } - char[] getPassword() + public char[] getPassword() { return _password; } - byte[] getPasswordBytes() + public byte[] getEncodedPassword() { byte[] byteArray = new byte[_password.length]; int index = 0; @@ -77,7 +73,14 @@ public class PlainUser implements Principal return byteArray; } - void setPassword(char[] password) + + + public void restorePassword(char[] password) + { + setPassword(password); + } + + public void setPassword(char[] password) { _password = password; _modified = true; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java index ef37e043a6..67f4b7344a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java @@ -22,14 +22,12 @@ package org.apache.qpid.server.security.auth.database; import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.login.AccountNotFoundException; import java.io.IOException; -import java.io.UnsupportedEncodingException; import java.security.Principal; -import java.util.Map; import java.util.List; - -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.login.AccountNotFoundException; +import java.util.Map; /** Represents a "user database" which is really a way of storing principals (i.e. usernames) and passwords. */ public interface PrincipalDatabase diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java index ff8851306f..4203cb0e07 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java @@ -27,14 +27,14 @@ import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.login.AccountNotFoundException; -import java.util.Properties; -import java.util.Map; -import java.util.HashMap; -import java.util.List; -import java.util.LinkedList; -import java.security.Principal; import java.io.IOException; import java.io.UnsupportedEncodingException; +import java.security.Principal; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Properties; public class PropertiesPrincipalDatabase implements PrincipalDatabase { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/management/AMQUserManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/management/AMQUserManagementMBean.java index 208130379e..1314a5d6a6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/management/AMQUserManagementMBean.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/management/AMQUserManagementMBean.java @@ -20,9 +20,14 @@ */ package org.apache.qpid.server.security.auth.management; -import java.io.IOException; -import java.security.Principal; -import java.util.List; +import org.apache.log4j.Logger; + +import org.apache.qpid.management.common.mbeans.UserManagement; +import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; +import org.apache.qpid.management.common.mbeans.annotations.MBeanOperation; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; import javax.management.JMException; import javax.management.openmbean.CompositeData; @@ -35,14 +40,9 @@ import javax.management.openmbean.TabularData; import javax.management.openmbean.TabularDataSupport; import javax.management.openmbean.TabularType; import javax.security.auth.login.AccountNotFoundException; - -import org.apache.log4j.Logger; -import org.apache.qpid.management.common.mbeans.UserManagement; -import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; -import org.apache.qpid.management.common.mbeans.annotations.MBeanOperation; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; -import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; +import java.io.IOException; +import java.security.Principal; +import java.util.List; /** MBean class for AMQUserManagementMBean. It implements all the management features exposed for managing users. */ @MBeanDescription("User Management Interface") diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java index 82eb7d3621..03cc12d06c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java @@ -20,21 +20,20 @@ */ package org.apache.qpid.server.security.auth.manager; -import javax.security.auth.Subject; -import javax.security.sasl.SaslException; -import javax.security.sasl.SaslServer; - import org.apache.qpid.amqp_1_0.transport.CallbackHanderSource; import org.apache.qpid.common.Closeable; import org.apache.qpid.server.plugins.Plugin; import org.apache.qpid.server.security.auth.AuthenticationResult; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + /** * Implementations of the AuthenticationManager are responsible for determining * the authenticity of a user's credentials. * * If the authentication is successful, the manager is responsible for producing a populated - * {@link Subject} containing the user's identity and zero or more principals representing + * {@link javax.security.auth.Subject} containing the user's identity and zero or more principals representing * groups to which the user belongs. * <p> * The {@link #initialise()} method is responsible for registering SASL mechanisms required by diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java index 978ad2b1f3..b5d70d9200 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java @@ -20,29 +20,10 @@ */ package org.apache.qpid.server.security.auth.manager; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.security.Security; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.TreeMap; - -import javax.security.auth.Subject; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.login.AccountNotFoundException; -import javax.security.sasl.Sasl; -import javax.security.sasl.SaslException; -import javax.security.sasl.SaslServer; -import javax.security.sasl.SaslServerFactory; - import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.Logger; + import org.apache.qpid.configuration.PropertyException; import org.apache.qpid.configuration.PropertyUtils; import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; @@ -55,6 +36,25 @@ import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialis import org.apache.qpid.server.security.auth.sasl.JCAProvider; import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; +import javax.security.auth.Subject; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.login.AccountNotFoundException; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslServerFactory; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.security.Security; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.TreeMap; + /** * Concrete implementation of the AuthenticationManager that determines if supplied @@ -95,9 +95,9 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan */ private final Map<String, Map<String, ?>> _serverCreationProperties = new HashMap<String, Map<String, ?>>(); - protected PrincipalDatabase _principalDatabase = null; + private PrincipalDatabase _principalDatabase = null; - protected AMQUserManagementMBean _mbean = null; + private AMQUserManagementMBean _mbean = null; public static final AuthenticationManagerPluginFactory<PrincipalDatabaseAuthenticationManager> FACTORY = new AuthenticationManagerPluginFactory<PrincipalDatabaseAuthenticationManager>() { @@ -160,13 +160,13 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan public String getPrincipalDatabaseClass() { - return _configuration.getString("principal-database.class"); + return getConfig().getString("principal-database.class"); } public Map<String,String> getPdClassAttributeMap() throws ConfigurationException { - final List<String> argumentNames = _configuration.getList("principal-database.attributes.attribute.name"); - final List<String> argumentValues = _configuration.getList("principal-database.attributes.attribute.value"); + final List<String> argumentNames = getConfig().getList("principal-database.attributes.attribute.name"); + final List<String> argumentValues = getConfig().getList("principal-database.attributes.attribute.value"); final Map<String,String> attributes = new HashMap<String,String>(argumentNames.size()); for (int i = 0; i < argumentNames.size(); i++) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java index b7985ad972..e27fd99f90 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java @@ -20,14 +20,14 @@ */ package org.apache.qpid.server.security.auth.rmi; -import javax.management.remote.JMXAuthenticator; -import javax.management.remote.JMXPrincipal; -import javax.security.auth.Subject; - import org.apache.qpid.server.security.auth.AuthenticationResult; import org.apache.qpid.server.security.auth.AuthenticationResult.AuthenticationStatus; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import javax.management.remote.JMXAuthenticator; +import javax.management.remote.JMXPrincipal; +import javax.security.auth.Subject; + public class RMIPasswordAuthenticator implements JMXAuthenticator { static final String UNABLE_TO_LOOKUP = "The broker was unable to lookup the user details"; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/AuthenticationProviderInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/AuthenticationProviderInitialiser.java index bc5d8a4f2b..c227aa14e8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/AuthenticationProviderInitialiser.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/AuthenticationProviderInitialiser.java @@ -20,10 +20,9 @@ */ package org.apache.qpid.server.security.auth.sasl; -import java.util.Map; - import javax.security.auth.callback.CallbackHandler; import javax.security.sasl.SaslServerFactory; +import java.util.Map; public interface AuthenticationProviderInitialiser { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java index d6f6c714e2..8711e1b385 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java @@ -20,11 +20,10 @@ */ package org.apache.qpid.server.security.auth.sasl; +import javax.security.sasl.SaslServerFactory; import java.security.Provider; import java.util.Map; -import javax.security.sasl.SaslServerFactory; - public class JCAProvider extends Provider { public JCAProvider(String name, Map<String, Class<? extends SaslServerFactory>> providerMap) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java index 5c13e03886..f4e8f800c6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java @@ -20,9 +20,10 @@ */ package org.apache.qpid.server.security.auth.sasl; -import java.io.IOException; -import java.security.Principal; -import java.util.Map; +import org.apache.commons.configuration.Configuration; +import org.apache.log4j.Logger; + +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; @@ -31,14 +32,9 @@ import javax.security.auth.callback.PasswordCallback; import javax.security.auth.callback.UnsupportedCallbackException; import javax.security.auth.login.AccountNotFoundException; import javax.security.sasl.AuthorizeCallback; - -import org.apache.commons.configuration.Configuration; - -import org.apache.log4j.Logger; - -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; -import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; -import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; +import java.io.IOException; +import java.security.Principal; +import java.util.Map; public abstract class UsernamePasswordInitialiser implements AuthenticationProviderInitialiser { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java index b4ee13fe6b..9e7db94216 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java @@ -20,11 +20,10 @@ */ package org.apache.qpid.server.security.auth.sasl; +import javax.security.auth.Subject; import java.security.Principal; import java.util.Set; -import javax.security.auth.Subject; - /** A principal that is just a wrapper for a simple username. */ public class UsernamePrincipal implements Principal { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainInitialiser.java index 7acc6322d1..860307215f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainInitialiser.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainInitialiser.java @@ -20,10 +20,10 @@ */ package org.apache.qpid.server.security.auth.sasl.amqplain; -import javax.security.sasl.SaslServerFactory; - import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser; +import javax.security.sasl.SaslServerFactory; + public class AmqPlainInitialiser extends UsernamePasswordInitialiser { public String getMechanismName() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServer.java index dee40e7069..eecc704011 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServer.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServer.java @@ -20,9 +20,9 @@ */ package org.apache.qpid.server.security.auth.sasl.amqplain; -import java.io.ByteArrayInputStream; -import java.io.DataInputStream; -import java.io.IOException; +import org.apache.qpid.framing.AMQFrameDecodingException; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.FieldTableFactory; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; @@ -32,10 +32,9 @@ import javax.security.auth.callback.UnsupportedCallbackException; import javax.security.sasl.AuthorizeCallback; import javax.security.sasl.SaslException; import javax.security.sasl.SaslServer; - -import org.apache.qpid.framing.AMQFrameDecodingException; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.FieldTableFactory; +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.IOException; public class AmqPlainSaslServer implements SaslServer { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServerFactory.java index 17d123eb0d..3a73f577fe 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServerFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/amqplain/AmqPlainSaslServerFactory.java @@ -20,13 +20,12 @@ */ package org.apache.qpid.server.security.auth.sasl.amqplain; -import java.util.Map; - import javax.security.auth.callback.CallbackHandler; import javax.security.sasl.Sasl; import javax.security.sasl.SaslException; import javax.security.sasl.SaslServer; import javax.security.sasl.SaslServerFactory; +import java.util.Map; public class AmqPlainSaslServerFactory implements SaslServerFactory { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousInitialiser.java index e35e999766..83369a84c7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousInitialiser.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousInitialiser.java @@ -20,53 +20,17 @@ */ package org.apache.qpid.server.security.auth.sasl.anonymous; -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.UnsupportedCallbackException; -import javax.security.sasl.SaslServerFactory; - -import org.apache.commons.configuration.Configuration; -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; -import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser; -import java.io.IOException; -import java.util.Map; +import javax.security.sasl.SaslServerFactory; -public class AnonymousInitialiser implements AuthenticationProviderInitialiser +public class AnonymousInitialiser extends UsernamePasswordInitialiser { public String getMechanismName() { return "ANONYMOUS"; } - public void initialise(String baseConfigPath, Configuration configuration, Map<String, PrincipalDatabase> principalDatabases) throws Exception - { - } - - public void initialise(PrincipalDatabase db) - { - } - - public CallbackHandler getCallbackHandler() - { - return new CallbackHandler() - { - - public Callback[] _callbacks; - - public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException - { - _callbacks =callbacks; - } - }; - } - - public Map<String, ?> getProperties() - { - return null; - } - public Class<? extends SaslServerFactory> getServerFactoryClassForJCARegistration() { return AnonymousSaslServerFactory.class; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousSaslServerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousSaslServerFactory.java index de695032ab..4650234972 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousSaslServerFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousSaslServerFactory.java @@ -20,15 +20,12 @@ */ package org.apache.qpid.server.security.auth.sasl.anonymous; -import org.apache.qpid.server.security.auth.sasl.amqplain.AmqPlainSaslServer; - -import java.util.Map; - import javax.security.auth.callback.CallbackHandler; import javax.security.sasl.Sasl; import javax.security.sasl.SaslException; import javax.security.sasl.SaslServer; import javax.security.sasl.SaslServerFactory; +import java.util.Map; public class AnonymousSaslServerFactory implements SaslServerFactory { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedInitialiser.java index 97f9a4e91a..842215c3eb 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedInitialiser.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedInitialiser.java @@ -20,8 +20,8 @@ */ package org.apache.qpid.server.security.auth.sasl.crammd5; -import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser; import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser; import javax.security.sasl.SaslServerFactory; import java.util.Map; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedSaslServer.java index f6cab084ea..a2d9fa5e3e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedSaslServer.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedSaslServer.java @@ -20,11 +20,11 @@ */ package org.apache.qpid.server.security.auth.sasl.crammd5; -import javax.security.sasl.SaslServer; -import javax.security.sasl.SaslException; +import javax.security.auth.callback.CallbackHandler; import javax.security.sasl.Sasl; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; import javax.security.sasl.SaslServerFactory; -import javax.security.auth.callback.CallbackHandler; import java.util.Enumeration; import java.util.Map; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedServerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedServerFactory.java index 5298b5cc63..4e82940439 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedServerFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedServerFactory.java @@ -20,13 +20,12 @@ */ package org.apache.qpid.server.security.auth.sasl.crammd5; -import java.util.Map; - import javax.security.auth.callback.CallbackHandler; import javax.security.sasl.Sasl; import javax.security.sasl.SaslException; import javax.security.sasl.SaslServer; import javax.security.sasl.SaslServerFactory; +import java.util.Map; public class CRAMMD5HashedServerFactory implements SaslServerFactory { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexInitialiser.java index 139818735f..478f195530 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexInitialiser.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexInitialiser.java @@ -21,16 +21,16 @@ package org.apache.qpid.server.security.auth.sasl.crammd5; import org.apache.qpid.server.security.auth.database.PrincipalDatabase; -import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser; import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; +import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser; -import javax.security.sasl.SaslServerFactory; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.login.AccountNotFoundException; -import java.util.Map; -import java.util.List; -import java.security.Principal; +import javax.security.sasl.SaslServerFactory; import java.io.IOException; +import java.security.Principal; +import java.util.List; +import java.util.Map; public class CRAMMD5HexInitialiser extends UsernamePasswordInitialiser { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexSaslServer.java index 192ff74bff..e19baaa7c6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexSaslServer.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexSaslServer.java @@ -20,11 +20,11 @@ */ package org.apache.qpid.server.security.auth.sasl.crammd5; -import javax.security.sasl.SaslServer; -import javax.security.sasl.SaslException; +import javax.security.auth.callback.CallbackHandler; import javax.security.sasl.Sasl; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; import javax.security.sasl.SaslServerFactory; -import javax.security.auth.callback.CallbackHandler; import java.util.Enumeration; import java.util.Map; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexServerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexServerFactory.java index ce0e19abf9..06c9108a73 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexServerFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HexServerFactory.java @@ -20,13 +20,12 @@ */ package org.apache.qpid.server.security.auth.sasl.crammd5; -import java.util.Map; - import javax.security.auth.callback.CallbackHandler; import javax.security.sasl.Sasl; import javax.security.sasl.SaslException; import javax.security.sasl.SaslServer; import javax.security.sasl.SaslServerFactory; +import java.util.Map; public class CRAMMD5HexServerFactory implements SaslServerFactory { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5Initialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5Initialiser.java index 264832888d..83e33d5491 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5Initialiser.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5Initialiser.java @@ -20,8 +20,8 @@ */ package org.apache.qpid.server.security.auth.sasl.crammd5; -import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser; import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser; import javax.security.sasl.SaslServerFactory; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainInitialiser.java index 1d16cd8755..67676d363e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainInitialiser.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainInitialiser.java @@ -20,10 +20,10 @@ */ package org.apache.qpid.server.security.auth.sasl.plain; -import javax.security.sasl.SaslServerFactory; - import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser; +import javax.security.sasl.SaslServerFactory; + public class PlainInitialiser extends UsernamePasswordInitialiser { public String getMechanismName() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainPasswordCallback.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainPasswordCallback.java index 7230e8ee53..0ea2f3c92e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainPasswordCallback.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainPasswordCallback.java @@ -20,9 +20,8 @@ */ package org.apache.qpid.server.security.auth.sasl.plain; -import java.util.Arrays; - import javax.security.auth.callback.PasswordCallback; +import java.util.Arrays; /** * Custom PasswordCallback for use during the PLAIN authentication process. diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java index 847a3a34ce..a811806c00 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServer.java @@ -20,16 +20,14 @@ */ package org.apache.qpid.server.security.auth.sasl.plain; -import java.io.IOException; - 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 java.io.IOException; public class PlainSaslServer implements SaslServer { @@ -53,57 +51,65 @@ public class PlainSaslServer implements SaslServer public byte[] evaluateResponse(byte[] response) throws SaslException { - try + int authzidNullPosition = findNullPosition(response, 0); + if (authzidNullPosition < 0) { - int authzidNullPosition = findNullPosition(response, 0); - if (authzidNullPosition < 0) - { - throw new SaslException("Invalid PLAIN encoding, authzid null terminator not found"); - } - int authcidNullPosition = findNullPosition(response, authzidNullPosition + 1); - if (authcidNullPosition < 0) - { - throw new SaslException("Invalid PLAIN encoding, authcid null terminator not found"); - } + throw new SaslException("Invalid PLAIN encoding, authzid null terminator not found"); + } + int authcidNullPosition = findNullPosition(response, authzidNullPosition + 1); + if (authcidNullPosition < 0) + { + throw new SaslException("Invalid PLAIN encoding, authcid null terminator not found"); + } + + PlainPasswordCallback passwordCb; + AuthorizeCallback authzCb; + try + { // we do not currently support authcid in any meaningful way - // String authcid = new String(response, 0, authzidNullPosition, "utf8"); String authzid = new String(response, authzidNullPosition + 1, authcidNullPosition - authzidNullPosition - 1, "utf8"); // TODO: should not get pwd as a String but as a char array... int passwordLen = response.length - authcidNullPosition - 1; String pwd = new String(response, authcidNullPosition + 1, passwordLen, "utf8"); - + // we do not care about the prompt but it throws if null NameCallback nameCb = new NameCallback("prompt", authzid); - PlainPasswordCallback passwordCb = new PlainPasswordCallback("prompt", false, pwd); - AuthorizeCallback authzCb = new AuthorizeCallback(authzid, authzid); + passwordCb = new PlainPasswordCallback("prompt", false, pwd); + authzCb = new AuthorizeCallback(authzid, authzid); Callback[] callbacks = new Callback[]{nameCb, passwordCb, authzCb}; _cbh.handle(callbacks); - if (passwordCb.isAuthenticated()) - { - _complete = true; - } - if (authzCb.isAuthorized() && _complete) - { - _authorizationId = authzCb.getAuthenticationID(); - return null; - } - else - { - throw new SaslException("Authentication failed"); - } } catch (IOException e) { + if(e instanceof SaslException) + { + throw (SaslException) e; + } throw new SaslException("Error processing data: " + e, e); } catch (UnsupportedCallbackException e) { throw new SaslException("Unable to obtain data from callback handler: " + e, e); } + + if (passwordCb.isAuthenticated()) + { + _complete = true; + } + + if (authzCb.isAuthorized() && _complete) + { + _authorizationId = authzCb.getAuthenticationID(); + return null; + } + else + { + throw new SaslException("Authentication failed"); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java index 3144bfbce6..445e5ef812 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java @@ -20,13 +20,12 @@ */ package org.apache.qpid.server.security.auth.sasl.plain; -import java.util.Map; - import javax.security.auth.callback.CallbackHandler; import javax.security.sasl.Sasl; import javax.security.sasl.SaslException; import javax.security.sasl.SaslServer; import javax.security.sasl.SaslServerFactory; +import java.util.Map; public class PlainSaslServerFactory implements SaslServerFactory { |