diff options
author | Robert Gemmell <robbie@apache.org> | 2011-06-09 10:38:20 +0000 |
---|---|---|
committer | Robert Gemmell <robbie@apache.org> | 2011-06-09 10:38:20 +0000 |
commit | b83ba1c0bc269d2b9dddd73dfe8a90d4d3723e58 (patch) | |
tree | 8d674ad91fbf4b4dff1a7610c76f63a1cc6a6259 | |
parent | 46af35ba4c7867098a1c5e1cea9bd24275cbad40 (diff) | |
download | qpid-python-b83ba1c0bc269d2b9dddd73dfe8a90d4d3723e58.tar.gz |
QPID-3296: update RMIPasswordAuthenticator to authenticate users via AuthenticationManager instead of a PrincipalDatabase
Applied patch from Keith Wall <keith.wall@gmail.com>
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1133781 13f79535-47bb-0310-9956-ffa450edef68
22 files changed, 572 insertions, 313 deletions
diff --git a/qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/AppInfo.java b/qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/AppInfo.java index a5d267282b..9bdd4b9d17 100644 --- a/qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/AppInfo.java +++ b/qpid/java/broker-plugins/experimental/info/src/main/java/org/apache/qpid/info/AppInfo.java @@ -74,8 +74,6 @@ public class AppInfo appInfoMap.put("port", sc.getPorts().toString()); appInfoMap.put("version", QpidProperties.getReleaseVersion()); appInfoMap.put("vhosts", "standalone"); - appInfoMap.put("JMXPrincipalDatabase", sc - .getJMXPrincipalDatabase()); appInfoMap.put("KeystorePath", sc.getKeystorePath()); appInfoMap.put("PluginDirectory", sc.getPluginDirectory()); appInfoMap.put("CertType", sc.getCertType()); diff --git a/qpid/java/broker-plugins/firewall/src/test/java/org/apache/qpid/server/security/access/FirewallConfigurationTest.java b/qpid/java/broker-plugins/firewall/src/test/java/org/apache/qpid/server/security/access/FirewallConfigurationTest.java index ebede414f4..c0cb4aedce 100644 --- a/qpid/java/broker-plugins/firewall/src/test/java/org/apache/qpid/server/security/access/FirewallConfigurationTest.java +++ b/qpid/java/broker-plugins/firewall/src/test/java/org/apache/qpid/server/security/access/FirewallConfigurationTest.java @@ -92,9 +92,6 @@ public class FirewallConfigurationTest extends InternalBrokerBaseCase out.write("\t\t\t\t</attributes>\n"); out.write("\t\t\t</principal-database>\n"); out.write("\t\t</principal-databases>\n"); - out.write("\t\t<jmx>\n"); - out.write("\t\t\t<principal-database>passwordfile</principal-database>\n"); - out.write("\t\t</jmx>\n"); out.write("\t\t<firewall>\n"); out.write("\t\t\t<xml fileName=\"" + fileB.getAbsolutePath() + "\"/>"); out.write("\t\t</firewall>\n"); @@ -192,9 +189,6 @@ public class FirewallConfigurationTest extends InternalBrokerBaseCase out.write("\t\t\t\t</attributes>\n"); out.write("\t\t\t</principal-database>\n"); out.write("\t\t</principal-databases>\n"); - out.write("\t\t<jmx>\n"); - out.write("\t\t\t<principal-database>passwordfile</principal-database>\n"); - out.write("\t\t</jmx>\n"); out.write("\t\t<firewall>\n"); out.write("\t\t\t<xml fileName=\"" + fileB.getAbsolutePath() + "\"/>"); out.write("\t\t</firewall>\n"); @@ -301,9 +295,6 @@ public class FirewallConfigurationTest extends InternalBrokerBaseCase out.write("\t\t\t\t</attributes>\n"); out.write("\t\t\t</principal-database>\n"); out.write("\t\t</principal-databases>\n"); - out.write("\t\t<jmx>\n"); - out.write("\t\t\t<principal-database>passwordfile</principal-database>\n"); - out.write("\t\t</jmx>\n"); out.write("\t\t<firewall>\n"); out.write("\t\t\t<rule access=\""+ ((allow) ? "allow" : "deny") +"\" network=\"127.0.0.1\"/>"); out.write("\t\t</firewall>\n"); diff --git a/qpid/java/broker/etc/config.xml b/qpid/java/broker/etc/config.xml index ec386ab669..c0f9b4df61 100644 --- a/qpid/java/broker/etc/config.xml +++ b/qpid/java/broker/etc/config.xml @@ -86,10 +86,6 @@ <allow-all /> <msg-auth>false</msg-auth> - - <jmx> - <principal-database>passwordfile</principal-database> - </jmx> </security> <virtualhosts>${conf}/virtualhosts.xml</virtualhosts> diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index 297f7abdb8..f152865a27 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -214,6 +214,13 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa + (_configFile == null ? "" : " Configuration file : " + _configFile); throw new ConfigurationException(message); } + + if (getListValue("security.jmx.principal-database").size() > 0) + { + String message = "Validation error : security/jmx/principal-database is no longer a supported element within the configuration xml." + + (_configFile == null ? "" : " Configuration file : " + _configFile); + throw new ConfigurationException(message); + } } /* @@ -533,11 +540,6 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa return getListValue(name); } - public List<String> getManagementPrincipalDBs() - { - return getListValue("security.jmx.principal-database"); - } - public int getFrameSize() { return getIntValue("advanced.framesize", DEFAULT_FRAME_SIZE); @@ -568,11 +570,6 @@ public class ServerConfiguration extends ConfigurationPlugin implements SignalHa return getBooleanValue("security.msg-auth"); } - public String getJMXPrincipalDatabase() - { - return getStringValue("security.jmx.principal-database"); - } - public String getManagementKeyStorePath() { return getStringValue("management.ssl.keyStorePath"); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java index d4b79134a2..79de0678f0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java @@ -20,6 +20,7 @@ */ package org.apache.qpid.server.handler; + import javax.security.sasl.SaslException; import javax.security.sasl.SaslServer; @@ -68,7 +69,7 @@ public class ConnectionSecureOkMethodHandler implements StateAwareMethodListener } MethodRegistry methodRegistry = session.getMethodRegistry(); AuthenticationResult authResult = authMgr.authenticate(ss, body.getResponse()); - switch (authResult.status) + switch (authResult.getStatus()) { case ERROR: Exception cause = authResult.getCause(); @@ -96,13 +97,14 @@ public class ConnectionSecureOkMethodHandler implements StateAwareMethodListener ConnectionStartOkMethodHandler.getConfiguredFrameSize(), ApplicationRegistry.getInstance().getConfiguration().getHeartBeatDelay()); session.writeFrame(tuneBody.generateFrame(0)); - session.setAuthorizedID(new UsernamePrincipal(ss.getAuthorizationID())); + final UsernamePrincipal principal = UsernamePrincipal.getUsernamePrincipalFromSubject(authResult.getSubject()); + session.setAuthorizedID(principal); disposeSaslServer(session); break; case CONTINUE: stateManager.changeState(AMQState.CONNECTION_NOT_AUTH); - ConnectionSecureBody secureBody = methodRegistry.createConnectionSecureBody(authResult.challenge); + ConnectionSecureBody secureBody = methodRegistry.createConnectionSecureBody(authResult.getChallenge()); session.writeFrame(secureBody.generateFrame(0)); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java index 4442f969c4..544bd62ed8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java @@ -88,7 +88,7 @@ public class ConnectionStartOkMethodHandler implements StateAwareMethodListener< MethodRegistry methodRegistry = session.getMethodRegistry(); - switch (authResult.status) + switch (authResult.getStatus()) { case ERROR: Exception cause = authResult.getCause(); @@ -121,7 +121,7 @@ public class ConnectionStartOkMethodHandler implements StateAwareMethodListener< case CONTINUE: stateManager.changeState(AMQState.CONNECTION_NOT_AUTH); - ConnectionSecureBody secureBody = methodRegistry.createConnectionSecureBody(authResult.challenge); + ConnectionSecureBody secureBody = methodRegistry.createConnectionSecureBody(authResult.getChallenge()); session.writeFrame(secureBody.generateFrame(0)); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java index 0334a856c1..6a34ff4a26 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java @@ -20,32 +20,6 @@ */ package org.apache.qpid.server.management; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.registry.IApplicationRegistry; -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; -import org.apache.qpid.server.security.auth.rmi.RMIPasswordAuthenticator; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.messages.ManagementConsoleMessages; - -import javax.management.JMException; -import javax.management.MBeanServer; -import javax.management.MBeanServerFactory; -import javax.management.ObjectName; -import javax.management.NotificationListener; -import javax.management.NotificationFilterSupport; -import javax.management.remote.JMXConnectorServer; -import javax.management.remote.JMXServiceURL; -import javax.management.remote.MBeanServerForwarder; -import javax.management.remote.JMXConnectionNotification; -import javax.management.remote.rmi.RMIConnectorServer; -import javax.management.remote.rmi.RMIJRMPServerImpl; -import javax.management.remote.rmi.RMIServerImpl; -import javax.rmi.ssl.SslRMIClientSocketFactory; -import javax.rmi.ssl.SslRMIServerSocketFactory; - import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; @@ -64,7 +38,31 @@ import java.rmi.server.RMIClientSocketFactory; import java.rmi.server.RMIServerSocketFactory; import java.rmi.server.UnicastRemoteObject; import java.util.HashMap; -import java.util.Map; + +import javax.management.JMException; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.NotificationFilterSupport; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.remote.JMXConnectionNotification; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXServiceURL; +import javax.management.remote.MBeanServerForwarder; +import javax.management.remote.rmi.RMIConnectorServer; +import javax.management.remote.rmi.RMIJRMPServerImpl; +import javax.management.remote.rmi.RMIServerImpl; +import javax.rmi.ssl.SslRMIClientSocketFactory; +import javax.rmi.ssl.SslRMIServerSocketFactory; + +import org.apache.commons.configuration.ConfigurationException; +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.messages.ManagementConsoleMessages; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.server.security.auth.rmi.RMIPasswordAuthenticator; /** * This class starts up an MBeanserver. If out of the box agent has been enabled then there are no @@ -113,12 +111,6 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry IApplicationRegistry appRegistry = ApplicationRegistry.getInstance(); int port = appRegistry.getConfiguration().getJMXManagementPort(); - //retrieve the Principal Database assigned to JMX authentication duties - String jmxDatabaseName = appRegistry.getConfiguration().getJMXPrincipalDatabase(); - Map<String, PrincipalDatabase> map = appRegistry.getDatabaseManager().getDatabases(); - PrincipalDatabase db = map.get(jmxDatabaseName); - - HashMap<String,Object> env = new HashMap<String,Object>(); //Socket factories for the RMIConnectorServer, either default or SLL depending on configuration RMIClientSocketFactory csf; @@ -200,7 +192,8 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry //add a JMXAuthenticator implementation the env map to authenticate the RMI based JMX connector server RMIPasswordAuthenticator rmipa = new RMIPasswordAuthenticator(); - rmipa.setPrincipalDatabase(db); + rmipa.setAuthenticationManager(appRegistry.getAuthenticationManager()); + HashMap<String,Object> env = new HashMap<String,Object>(); env.put(JMXConnectorServer.AUTHENTICATOR, rmipa); /* diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java index 380f51e308..ce6bd3ee33 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java @@ -27,7 +27,6 @@ import java.lang.reflect.Proxy; import java.security.AccessControlContext; import java.security.AccessController; import java.security.Principal; -import java.util.Properties; import java.util.Set; import javax.management.Attribute; @@ -65,7 +64,6 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati public final static String READONLY = "readonly"; private final static String DELEGATE = "JMImplementation:type=MBeanServerDelegate"; private MBeanServer _mbs; - private static Properties _userRoles = new Properties(); private static ManagementActor _logActor; public static MBeanServerForwarder newProxyInstance() 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 62967ef7eb..8c2d60a660 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 @@ -20,42 +20,93 @@ */ package org.apache.qpid.server.security.auth; +import javax.security.auth.Subject; + +/** + * Encapsulates the result of an attempt to authenticate. + * <p> + * The authentication status describes the overall outcome. + * <p> + * <ol> + * <li>If authentication status is SUCCESS, the subject will be populated. + * </li> + * <li>If authentication status is CONTINUE, the authentication has failed because the user + * supplied incorrect credentials (etc). If the authentication requires it, the next challenge + * is made available. + * </li> + * <li>If authentication status is ERROR , the authentication decision could not be made due + * to a failure (such as an external system), the {@link AuthenticationResult#getCause()} + * will provide the underlying exception. + * </li> + * </ol> + * + */ public class AuthenticationResult { public enum AuthenticationStatus { - SUCCESS, CONTINUE, ERROR + /** Authentication successful */ + SUCCESS, + /** Authentication not successful due to credentials problem etc */ + CONTINUE, + /** Problem prevented the authentication from being made e.g. failure of an external system */ + ERROR } - public AuthenticationStatus status; - public byte[] challenge; - - private Exception cause; + public final AuthenticationStatus _status; + public final byte[] _challenge; + private final Exception _cause; + private final Subject _subject; - public AuthenticationResult(AuthenticationStatus status) + public AuthenticationResult(final AuthenticationStatus status) { this(null, status, null); } - public AuthenticationResult(byte[] challenge, AuthenticationStatus status) + public AuthenticationResult(final byte[] challenge, final AuthenticationStatus status) { this(challenge, status, null); } - public AuthenticationResult(AuthenticationStatus error, Exception cause) + public AuthenticationResult(final AuthenticationStatus error, final Exception cause) { this(null, error, cause); } - public AuthenticationResult(byte[] challenge, AuthenticationStatus status, Exception cause) + public AuthenticationResult(final byte[] challenge, final AuthenticationStatus status, final Exception cause) + { + this._status = status; + this._challenge = challenge; + this._cause = cause; + this._subject = null; + } + + public AuthenticationResult(final Subject subject) { - this.status = status; - this.challenge = challenge; - this.cause = cause; + this._status = AuthenticationStatus.SUCCESS; + this._challenge = null; + this._cause = null; + this._subject = subject; } public Exception getCause() { - return cause; + return _cause; + } + + public AuthenticationStatus getStatus() + { + return _status; + } + + public byte[] getChallenge() + { + return _challenge; } + + public Subject getSubject() + { + return _subject; + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java index e9276e1b0e..a22c66c73d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java @@ -23,6 +23,7 @@ package org.apache.qpid.server.security.auth.database; import java.io.FileNotFoundException; import java.io.IOException; import java.lang.reflect.Method; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -170,18 +171,13 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab { AMQUserManagementMBean _mbean = new AMQUserManagementMBean(); - List<String> principalDBs = config.getManagementPrincipalDBs(); - if (principalDBs.isEmpty()) - { - throw new ConfigurationException("No principal-database specified for jmx security"); - } - String databaseName = principalDBs.get(0); - PrincipalDatabase database = getDatabases().get(databaseName); - if (database == null) + final Collection<PrincipalDatabase> dbs = getDatabases().values(); + if (dbs.size() == 0) { - throw new ConfigurationException("Principal-database '" + databaseName + "' not found"); + throw new ConfigurationException("Principal-database not found"); } + final PrincipalDatabase database = dbs.iterator().next(); _mbean.setPrincipalDatabase(database); _mbean.register(); 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 39e1e07c57..c1ef4c8ff5 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 @@ -32,9 +32,43 @@ import org.apache.qpid.server.security.auth.AuthenticationResult; */ public interface AuthenticationManager extends Closeable { + + /** + * Gets the SASL mechanisms known to this manager. + * + * @return SASL mechanism names, space separated. + */ String getMechanisms(); + /** + * Creates a SASL server for the specified mechanism name for the given + * fully qualified domain name. + * + * @param mechanism mechanism name + * @param localFQDN domain name + * + * @return SASL server + * @throws SaslException + */ SaslServer createSaslServer(String mechanism, String localFQDN) throws SaslException; + /** + * Authenticates a user using SASL negotiation. + * + * @param server SASL server + * @param response SASL response to process + * + * @return authentication result + */ AuthenticationResult authenticate(SaslServer server, byte[] response); + + /** + * Authenticates a user using their username and password. + * + * @param username username + * @param password password + * + * @return authentication result + */ + AuthenticationResult authenticate(String username, String password); } 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 d10ad2c170..d36bbc4f46 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 @@ -23,12 +23,16 @@ package org.apache.qpid.server.security.auth.manager; import org.apache.log4j.Logger; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.security.auth.AuthenticationResult.AuthenticationStatus; import org.apache.qpid.server.security.auth.database.PrincipalDatabase; import org.apache.qpid.server.security.auth.sasl.JCAProvider; 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.AuthenticationResult; +import javax.security.auth.Subject; import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.login.AccountNotFoundException; import javax.security.sasl.SaslServerFactory; import javax.security.sasl.SaslServer; import javax.security.sasl.SaslException; @@ -163,7 +167,9 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan if (server.isComplete()) { - return new AuthenticationResult(challenge, AuthenticationResult.AuthenticationStatus.SUCCESS); + final Subject subject = new Subject(); + subject.getPrincipals().add(new UsernamePrincipal(server.getAuthorizationID())); + return new AuthenticationResult(subject); } else { @@ -181,4 +187,31 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan _mechanisms = null; Security.removeProvider(PROVIDER_NAME); } + + /** + * @see org.apache.qpid.server.security.auth.manager.AuthenticationManager#authenticate(String, String) + */ + @Override + public AuthenticationResult authenticate(final String username, final String password) + { + final PrincipalDatabase db = ApplicationRegistry.getInstance().getDatabaseManager().getDatabases().values().iterator().next(); + + try + { + if (db.verifyPassword(username, password.toCharArray())) + { + final Subject subject = new Subject(); + subject.getPrincipals().add(new UsernamePrincipal(username)); + return new AuthenticationResult(subject); + } + else + { + return new AuthenticationResult(AuthenticationStatus.CONTINUE); + } + } + catch (AccountNotFoundException e) + { + return new AuthenticationResult(AuthenticationStatus.CONTINUE); + } + } } 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 0cbbccb3b8..b7985ad972 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,13 @@ */ package org.apache.qpid.server.security.auth.rmi; -import java.util.Collections; - import javax.management.remote.JMXAuthenticator; import javax.management.remote.JMXPrincipal; import javax.security.auth.Subject; -import javax.security.auth.login.AccountNotFoundException; -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +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; public class RMIPasswordAuthenticator implements JMXAuthenticator { @@ -39,15 +38,15 @@ public class RMIPasswordAuthenticator implements JMXAuthenticator static final String CREDENTIALS_REQUIRED = "User details are required. " + "Please ensure you are using an up to date management console to connect."; - private PrincipalDatabase _db = null; + private AuthenticationManager _authenticationManager = null; public RMIPasswordAuthenticator() { } - - public void setPrincipalDatabase(PrincipalDatabase pd) + + public void setAuthenticationManager(final AuthenticationManager authenticationManager) { - this._db = pd; + _authenticationManager = authenticationManager; } public Subject authenticate(Object credentials) throws SecurityException @@ -65,50 +64,39 @@ public class RMIPasswordAuthenticator implements JMXAuthenticator } } - // Verify that required number of credential's. + // Verify that required number of credentials. final String[] userCredentials = (String[]) credentials; if (userCredentials.length != 2) { throw new SecurityException(SHOULD_HAVE_2_ELEMENTS); } - String username = (String) userCredentials[0]; - String password = (String) userCredentials[1]; + final String username = (String) userCredentials[0]; + final String password = (String) userCredentials[1]; - // Verify that all required credential's are actually present. + // Verify that all required credentials are actually present. if (username == null || password == null) { throw new SecurityException(SHOULD_BE_NON_NULL); } - // Verify that a PD has been set. - if (_db == null) + // Verify that an AuthenticationManager has been set. + if (_authenticationManager == null) { throw new SecurityException(UNABLE_TO_LOOKUP); } - - boolean authenticated = false; + final AuthenticationResult result = _authenticationManager.authenticate(username, password); - // Perform authentication - try + if (AuthenticationStatus.ERROR.equals(result.getStatus())) { - if (_db.verifyPassword(username, password.toCharArray())) - { - authenticated = true; - } - } - catch (AccountNotFoundException e) - { - throw new SecurityException(INVALID_CREDENTIALS); // XXX + throw new SecurityException("Authentication manager failed", result.getCause()); } - - if (authenticated) + else if (AuthenticationStatus.SUCCESS.equals(result.getStatus())) { - //credential's check out, return the appropriate JAAS Subject - return new Subject(true, - Collections.singleton(new JMXPrincipal(username)), - Collections.EMPTY_SET, - Collections.EMPTY_SET); + final Subject subject = result.getSubject(); + subject.getPrincipals().add(new JMXPrincipal(username)); + subject.setReadOnly(); + return subject; } else { 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 d7c8383690..b4ee13fe6b 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 @@ -21,14 +21,21 @@ package org.apache.qpid.server.security.auth.sasl; 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 { - private String _name; + private final String _name; public UsernamePrincipal(String name) { + if (name == null) + { + throw new IllegalArgumentException("name cannot be null"); + } _name = name; } @@ -41,4 +48,53 @@ public class UsernamePrincipal implements Principal { return _name; } + + /** + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() + { + final int prime = 31; + return prime * _name.hashCode(); + } + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) + { + if (this == obj) + { + return true; + } + else + { + if (obj instanceof UsernamePrincipal) + { + UsernamePrincipal other = (UsernamePrincipal) obj; + return _name.equals(other._name); + } + else + { + return false; + } + } + } + + public static UsernamePrincipal getUsernamePrincipalFromSubject(final Subject authSubject) + { + if (authSubject == null) + { + throw new IllegalArgumentException("No authenticated subject."); + } + + final Set<UsernamePrincipal> principals = authSubject.getPrincipals(UsernamePrincipal.class); + if (principals.size() != 1) + { + throw new IllegalArgumentException("Can't find single UsernamePrincipal in authenticated subject"); + } + return principals.iterator().next(); + } } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java index 43540c88a1..494003c8a0 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java @@ -23,24 +23,18 @@ package org.apache.qpid.server.configuration; import java.io.File; import java.io.FileWriter; import java.io.IOException; -import java.io.RandomAccessFile; import java.util.List; import java.util.Locale; -import junit.framework.TestCase; - import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.XMLConfiguration; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.protocol.AMQProtocolEngine; -import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry; import org.apache.qpid.server.util.InternalBrokerBaseCase; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -import org.apache.qpid.transport.TestNetworkDriver; public class ServerConfigurationTest extends InternalBrokerBaseCase { @@ -320,20 +314,6 @@ public class ServerConfigurationTest extends InternalBrokerBaseCase assertEquals(true, serverConfig.getMsgAuth()); } - public void testGetJMXPrincipalDatabase() throws ConfigurationException - { - // Check default - ServerConfiguration serverConfig = new ServerConfiguration(_config); - serverConfig.initialise(); - assertEquals(null, serverConfig.getJMXPrincipalDatabase()); - - // Check value we set - _config.setProperty("security.jmx.principal-database", "a"); - serverConfig = new ServerConfiguration(_config); - serverConfig.initialise(); - assertEquals("a", serverConfig.getJMXPrincipalDatabase()); - } - public void testGetManagementKeyStorePath() throws ConfigurationException { // Check default @@ -831,9 +811,6 @@ public class ServerConfigurationTest extends InternalBrokerBaseCase out.write("\t\t\t\t</attributes>\n"); out.write("\t\t\t</principal-database>\n"); out.write("\t\t</principal-databases>\n"); - out.write("\t\t<jmx>\n"); - out.write("\t\t\t<principal-database>passwordfile</principal-database>\n"); - out.write("\t\t</jmx>\n"); out.write("\t\t<firewall>\n"); out.write("\t\t\t<rule access=\""+ ((allow) ? "allow" : "deny") +"\" network=\"127.0.0.1\"/>"); out.write("\t\t</firewall>\n"); @@ -881,9 +858,6 @@ public class ServerConfigurationTest extends InternalBrokerBaseCase out.write("\t\t\t\t</attributes>\n"); out.write("\t\t\t</principal-database>\n"); out.write("\t\t</principal-databases>\n"); - out.write("\t\t<jmx>\n"); - out.write("\t\t\t<principal-database>passwordfile</principal-database>\n"); - out.write("\t\t</jmx>\n"); out.write("\t\t<firewall>\n"); out.write("\t\t\t<rule access=\"allow\" network=\"127.0.0.1\"/>"); out.write("\t\t</firewall>\n"); @@ -986,9 +960,6 @@ public class ServerConfigurationTest extends InternalBrokerBaseCase out.write("\t\t\t\t</attributes>\n"); out.write("\t\t\t</principal-database>\n"); out.write("\t\t</principal-databases>\n"); - out.write("\t\t<jmx>\n"); - out.write("\t\t\t<principal-database>passwordfile</principal-database>\n"); - out.write("\t\t</jmx>\n"); out.write("\t\t<firewall>\n"); out.write("\t\t\t<rule access=\"allow\" network=\"127.0.0.1\"/>"); out.write("\t\t</firewall>\n"); @@ -1489,4 +1460,31 @@ public class ServerConfigurationTest extends InternalBrokerBaseCase ce.getMessage()); } } + + /* + * Tests that the old element security.jmx.principal-databases (that used to define the + * principal database used for JMX authentication) is rejected. + */ + public void testManagementPrincipalDatabaseRejected() throws ConfigurationException + { + // Check default + ServerConfiguration serverConfig = new ServerConfiguration(_config); + serverConfig.initialise(); + + // Check value we set + _config.setProperty("security.jmx.principal-database(0)", "mydb"); + serverConfig = new ServerConfiguration(_config); + + try + { + serverConfig.initialise(); + fail("Exception not thrown"); + } + catch (ConfigurationException ce) + { + assertEquals("Incorrect error message", + "Validation error : security/jmx/principal-database is no longer a supported element within the configuration xml.", + ce.getMessage()); + } + } } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManagerTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManagerTest.java index f51ce0b6c6..5a9026cb64 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManagerTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManagerTest.java @@ -23,11 +23,13 @@ package org.apache.qpid.server.security.auth.manager; import java.security.Provider; import java.security.Security; +import javax.security.auth.Subject; import javax.security.sasl.SaslException; import javax.security.sasl.SaslServer; import org.apache.qpid.server.security.auth.AuthenticationResult; import org.apache.qpid.server.security.auth.AuthenticationResult.AuthenticationStatus; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; import org.apache.qpid.server.util.InternalBrokerBaseCase; /** @@ -89,17 +91,18 @@ public class PrincipalDatabaseAuthenticationManagerTest extends InternalBrokerBa } /** - * * Tests that the authenticate method correctly interprets an * authentication success. * */ - public void testAuthenticationSuccess() throws Exception + public void testSaslAuthenticationSuccess() throws Exception { SaslServer testServer = createTestSaslServer(true, false); AuthenticationResult result = _manager.authenticate(testServer, "12345".getBytes()); - assertEquals(AuthenticationStatus.SUCCESS, result.status); + final Subject subject = result.getSubject(); + assertTrue(subject.getPrincipals().contains(new UsernamePrincipal("guest"))); + assertEquals(AuthenticationStatus.SUCCESS, result.getStatus()); } /** @@ -108,12 +111,13 @@ public class PrincipalDatabaseAuthenticationManagerTest extends InternalBrokerBa * authentication not complete. * */ - public void testAuthenticationNotCompleted() throws Exception + public void testSaslAuthenticationNotCompleted() throws Exception { SaslServer testServer = createTestSaslServer(false, false); AuthenticationResult result = _manager.authenticate(testServer, "12345".getBytes()); - assertEquals(AuthenticationStatus.CONTINUE, result.status); + assertNull(result.getSubject()); + assertEquals(AuthenticationStatus.CONTINUE, result.getStatus()); } /** @@ -122,12 +126,39 @@ public class PrincipalDatabaseAuthenticationManagerTest extends InternalBrokerBa * authentication error. * */ - public void testAuthenticationError() throws Exception + public void testSaslAuthenticationError() throws Exception { SaslServer testServer = createTestSaslServer(false, true); AuthenticationResult result = _manager.authenticate(testServer, "12345".getBytes()); - assertEquals(AuthenticationStatus.ERROR, result.status); + assertNull(result.getSubject()); + assertEquals(AuthenticationStatus.ERROR, result.getStatus()); + } + + /** + * Tests that the authenticate method correctly interprets an + * authentication success. + * + */ + public void testNonSaslAuthenticationSuccess() throws Exception + { + AuthenticationResult result = _manager.authenticate("guest", "guest"); + final Subject subject = result.getSubject(); + assertFalse("Subject should not be set read-only", subject.isReadOnly()); + assertTrue(subject.getPrincipals().contains(new UsernamePrincipal("guest"))); + assertEquals(AuthenticationStatus.SUCCESS, result.getStatus()); + } + + /** + * Tests that the authenticate method correctly interprets an + * authentication success. + * + */ + public void testNonSaslAuthenticationNotCompleted() throws Exception + { + AuthenticationResult result = _manager.authenticate("guest", "wrongpassword"); + assertNull(result.getSubject()); + assertEquals(AuthenticationStatus.CONTINUE, result.getStatus()); } /** @@ -179,7 +210,7 @@ public class PrincipalDatabaseAuthenticationManagerTest extends InternalBrokerBa @Override public String getAuthorizationID() { - return null; + return complete ? "guest" : null; } @Override diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticatorTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticatorTest.java index e8c24da68d..eb713e3712 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticatorTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticatorTest.java @@ -20,188 +20,124 @@ */ package org.apache.qpid.server.security.auth.rmi; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; import java.util.Collections; import javax.management.remote.JMXPrincipal; import javax.security.auth.Subject; - -import org.apache.qpid.server.security.auth.database.Base64MD5PasswordFilePrincipalDatabase; -import org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; import junit.framework.TestCase; +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; + +/** + * Tests the RMIPasswordAuthenticator and its collaboration with the AuthenticationManager. + * + */ public class RMIPasswordAuthenticatorTest extends TestCase { private final String USERNAME = "guest"; private final String PASSWORD = "guest"; - private final String B64_MD5HASHED_PASSWORD = "CE4DQ6BIb/BVMN9scFyLtA=="; private RMIPasswordAuthenticator _rmipa; - - private Base64MD5PasswordFilePrincipalDatabase _md5Pd; - private File _md5PwdFile; - - private PlainPasswordFilePrincipalDatabase _plainPd; - private File _plainPwdFile; - - private Subject testSubject; + private String[] _credentials; protected void setUp() throws Exception { _rmipa = new RMIPasswordAuthenticator(); - _md5Pd = new Base64MD5PasswordFilePrincipalDatabase(); - _md5PwdFile = createTempPasswordFile(this.getClass().getName()+"md5pwd", USERNAME, B64_MD5HASHED_PASSWORD); - _md5Pd.setPasswordFile(_md5PwdFile.getAbsolutePath()); - - _plainPd = new PlainPasswordFilePrincipalDatabase(); - _plainPwdFile = createTempPasswordFile(this.getClass().getName()+"plainpwd", USERNAME, PASSWORD); - _plainPd.setPasswordFile(_plainPwdFile.getAbsolutePath()); - - testSubject = new Subject(true, + _credentials = new String[] {USERNAME, PASSWORD}; + } + + /** + * Tests a successful authentication. Ensures that a populated read-only subject it returned. + */ + public void testAuthenticationSuccess() + { + final Subject expectedSubject = new Subject(true, Collections.singleton(new JMXPrincipal(USERNAME)), Collections.EMPTY_SET, Collections.EMPTY_SET); - } - - private File createTempPasswordFile(String filenamePrefix, String user, String password) - { - try - { - File testFile = File.createTempFile(filenamePrefix,"tmp"); - testFile.deleteOnExit(); - BufferedWriter writer = new BufferedWriter(new FileWriter(testFile)); + _rmipa.setAuthenticationManager(createTestAuthenticationManager(true, null)); - writer.write(user + ":" + password); - writer.newLine(); - writer.flush(); - writer.close(); - - return testFile; - } - catch (IOException e) - { - fail("Unable to create temporary test password file." + e.getMessage()); - } + Subject newSubject = _rmipa.authenticate(_credentials); + assertTrue("Subject must be readonly", newSubject.isReadOnly()); + assertTrue("Returned subject does not equal expected value", + newSubject.equals(expectedSubject)); - return null; } - - - //********** Test Methods *********// - - public void testAuthenticate() + /** + * Tests a unsuccessful authentication. + */ + public void testUsernameOrPasswordInvalid() { - String[] credentials; - Subject newSubject; - - // Test when no PD has been set - try - { - credentials = new String[]{USERNAME, PASSWORD}; - newSubject = _rmipa.authenticate(credentials); - fail("SecurityException expected due to lack of principal database"); - } - catch (SecurityException se) - { - assertEquals("Unexpected exception message", - RMIPasswordAuthenticator.UNABLE_TO_LOOKUP, se.getMessage()); - } - - //The PrincipalDatabase's are tested primarily by their own tests, but - //minimal tests are done here to exercise their usage in this area. + _rmipa.setAuthenticationManager(createTestAuthenticationManager(false, null)); - // Test correct passwords are verified with an MD5 PD try { - _rmipa.setPrincipalDatabase(_md5Pd); - credentials = new String[]{USERNAME, PASSWORD}; - newSubject = _rmipa.authenticate(credentials); - assertTrue("Returned subject does not equal expected value", - newSubject.equals(testSubject)); - } - catch (Exception e) - { - fail("Unexpected Exception:" + e.getMessage()); - } - - // Test incorrect passwords are not verified with an MD5 PD - try - { - credentials = new String[]{USERNAME, PASSWORD+"incorrect"}; - newSubject = _rmipa.authenticate(credentials); - fail("SecurityException expected due to incorrect password"); + _rmipa.authenticate(_credentials); + fail("Exception not thrown"); } catch (SecurityException se) { assertEquals("Unexpected exception message", RMIPasswordAuthenticator.INVALID_CREDENTIALS, se.getMessage()); - } - - // Test non-existent accounts are not verified with an MD5 PD - try - { - credentials = new String[]{USERNAME+"invalid", PASSWORD}; - newSubject = _rmipa.authenticate(credentials); - fail("SecurityException expected due to non-existant account"); - } - catch (SecurityException se) - { - assertEquals("Unexpected exception message", - RMIPasswordAuthenticator.INVALID_CREDENTIALS, se.getMessage()); - } - // Test correct passwords are verified with a Plain PD - try - { - _rmipa.setPrincipalDatabase(_plainPd); - credentials = new String[]{USERNAME, PASSWORD}; - newSubject = _rmipa.authenticate(credentials); - assertTrue("Returned subject does not equal expected value", - newSubject.equals(testSubject)); - } - catch (Exception e) - { - fail("Unexpected Exception"); } + } + + /** + * Tests case where authentication system itself fails. + */ + public void testAuthenticationFailure() + { + final Exception mockAuthException = new Exception("Mock Auth system failure"); + _rmipa.setAuthenticationManager(createTestAuthenticationManager(false, mockAuthException)); - // Test incorrect passwords are not verified with a Plain PD try { - credentials = new String[]{USERNAME, PASSWORD+"incorrect"}; - newSubject = _rmipa.authenticate(credentials); - fail("SecurityException expected due to incorrect password"); + _rmipa.authenticate(_credentials); + fail("Exception not thrown"); } catch (SecurityException se) { - assertEquals("Unexpected exception message", - RMIPasswordAuthenticator.INVALID_CREDENTIALS, se.getMessage()); + assertEquals("Initial cause not found", mockAuthException, se.getCause()); } - - // Test non-existent accounts are not verified with an Plain PD + } + + + /** + * Tests case where authentication manager is not set. + */ + public void testNullAuthenticationManager() + { try { - credentials = new String[]{USERNAME+"invalid", PASSWORD}; - newSubject = _rmipa.authenticate(credentials); - fail("SecurityException expected due to non existant account"); + _rmipa.authenticate(_credentials); + fail("SecurityException expected due to lack of authentication manager"); } catch (SecurityException se) { assertEquals("Unexpected exception message", - RMIPasswordAuthenticator.INVALID_CREDENTIALS, se.getMessage()); + RMIPasswordAuthenticator.UNABLE_TO_LOOKUP, se.getMessage()); } + } + /** + * Tests case where arguments are non-Strings.. + */ + public void testWithNonStringArrayArgument() + { // Test handling of non-string credential's + final Object[] objCredentials = new Object[]{USERNAME, PASSWORD}; try { - Object[] objCredentials = new Object[]{USERNAME, PASSWORD}; - newSubject = _rmipa.authenticate(objCredentials); + _rmipa.authenticate(objCredentials); fail("SecurityException expected due to non string[] credentials"); } catch (SecurityException se) @@ -209,12 +145,18 @@ public class RMIPasswordAuthenticatorTest extends TestCase assertEquals("Unexpected exception message", RMIPasswordAuthenticator.SHOULD_BE_STRING_ARRAY, se.getMessage()); } - - // Test handling of incorrect number of credential's + } + + /** + * Tests case where there are too many, too few or null arguments. + */ + public void testWithIllegalNumberOfArguments() + { + // Test handling of incorrect number of credentials try { - credentials = new String[]{USERNAME, PASSWORD, PASSWORD}; - newSubject = _rmipa.authenticate(credentials); + _credentials = new String[]{USERNAME, PASSWORD, PASSWORD}; + _rmipa.authenticate(_credentials); fail("SecurityException expected due to supplying wrong number of credentials"); } catch (SecurityException se) @@ -223,12 +165,12 @@ public class RMIPasswordAuthenticatorTest extends TestCase RMIPasswordAuthenticator.SHOULD_HAVE_2_ELEMENTS, se.getMessage()); } - // Test handling of null credential's + // Test handling of null credentials try { //send a null array - credentials = null; - newSubject = _rmipa.authenticate(credentials); + _credentials = null; + _rmipa.authenticate(_credentials); fail("SecurityException expected due to not supplying an array of credentials"); } catch (SecurityException se) @@ -240,8 +182,8 @@ public class RMIPasswordAuthenticatorTest extends TestCase try { //send a null password - credentials = new String[]{USERNAME, null}; - newSubject = _rmipa.authenticate(credentials); + _credentials = new String[]{USERNAME, null}; + _rmipa.authenticate(_credentials); fail("SecurityException expected due to sending a null password"); } catch (SecurityException se) @@ -253,8 +195,8 @@ public class RMIPasswordAuthenticatorTest extends TestCase try { //send a null username - credentials = new String[]{null, PASSWORD}; - newSubject = _rmipa.authenticate(credentials); + _credentials = new String[]{null, PASSWORD}; + _rmipa.authenticate(_credentials); fail("SecurityException expected due to sending a null username"); } catch (SecurityException se) @@ -264,4 +206,50 @@ public class RMIPasswordAuthenticatorTest extends TestCase } } + private AuthenticationManager createTestAuthenticationManager(final boolean successfulAuth, final Exception exception) + { + return new AuthenticationManager() + { + @Override + public void close() + { + throw new UnsupportedOperationException(); + } + + @Override + public String getMechanisms() + { + throw new UnsupportedOperationException(); + } + + @Override + public SaslServer createSaslServer(String mechanism, String localFQDN) throws SaslException + { + throw new UnsupportedOperationException(); + } + + @Override + public AuthenticationResult authenticate(SaslServer server, byte[] response) + { + throw new UnsupportedOperationException(); + } + + @Override + public AuthenticationResult authenticate(String username, String password) + { + if (exception != null) { + return new AuthenticationResult(AuthenticationStatus.ERROR, exception); + } + else if (successfulAuth) + { + return new AuthenticationResult(new Subject()); + } + else + { + return new AuthenticationResult(AuthenticationStatus.CONTINUE); + } + } + }; + } + } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipalTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipalTest.java new file mode 100644 index 0000000000..8bff22115e --- /dev/null +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipalTest.java @@ -0,0 +1,124 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.auth.sasl; + +import java.security.Principal; +import javax.security.auth.Subject; +import junit.framework.TestCase; + +/** + * Tests the UsernamePrincipal. + * + */ +public class UsernamePrincipalTest extends TestCase +{ + public void testEqualitySameObject() + { + final UsernamePrincipal principal = new UsernamePrincipal("string"); + assertTrue(principal.equals(principal)); + } + + public void testEqualitySameName() + { + final String string = "string"; + final UsernamePrincipal principal1 = new UsernamePrincipal(string); + final UsernamePrincipal principal2 = new UsernamePrincipal(string); + assertTrue(principal1.equals(principal2)); + } + + public void testEqualityEqualName() + { + final UsernamePrincipal principal1 = new UsernamePrincipal(new String("string")); + final UsernamePrincipal principal2 = new UsernamePrincipal(new String("string")); + assertTrue(principal1.equals(principal2)); + } + + public void testInequalityDifferentUserPrincipals() + { + UsernamePrincipal principal1 = new UsernamePrincipal("string1"); + UsernamePrincipal principal2 = new UsernamePrincipal("string2"); + assertFalse(principal1.equals(principal2)); + } + + public void testInequalityNonUserPrincipal() + { + UsernamePrincipal principal = new UsernamePrincipal("string"); + assertFalse(principal.equals(new String("string"))); + } + + public void testInequalityNull() + { + UsernamePrincipal principal = new UsernamePrincipal("string"); + assertFalse(principal.equals(null)); + } + + public void testGetUsernamePrincipalFromSubject() + { + final UsernamePrincipal expected = new UsernamePrincipal("name"); + final Principal other = new Principal() + { + + @Override + public String getName() + { + return "otherprincipal"; + } + }; + + final Subject subject = new Subject(); + subject.getPrincipals().add(expected); + subject.getPrincipals().add(other); + + final UsernamePrincipal actual = UsernamePrincipal.getUsernamePrincipalFromSubject(subject); + assertSame(expected, actual); + } + + public void testUsernamePrincipalNotInSubject() + { + try + { + UsernamePrincipal.getUsernamePrincipalFromSubject(new Subject()); + fail("Exception not thrown"); + } + catch (IllegalArgumentException iae) + { + // PASS + } + } + + public void testTooManyUsernamePrincipalInSubject() + { + final Subject subject = new Subject(); + subject.getPrincipals().add(new UsernamePrincipal("name1")); + subject.getPrincipals().add(new UsernamePrincipal("name2")); + try + { + + UsernamePrincipal.getUsernamePrincipalFromSubject(subject); + fail("Exception not thrown"); + } + catch (IllegalArgumentException iae) + { + // PASS + } + } + +} diff --git a/qpid/java/systests/etc/config-systests-ServerConfigurationTest-New.xml b/qpid/java/systests/etc/config-systests-ServerConfigurationTest-New.xml index 39805cbc48..1c7c7bb60f 100644 --- a/qpid/java/systests/etc/config-systests-ServerConfigurationTest-New.xml +++ b/qpid/java/systests/etc/config-systests-ServerConfigurationTest-New.xml @@ -57,10 +57,6 @@ </attributes> </principal-database> </principal-databases> - - <jmx> - <principal-database>passwordfile</principal-database> - </jmx> </security> <virtualhosts>${conf}/virtualhosts-ServerConfigurationTest-New.xml</virtualhosts> diff --git a/qpid/java/systests/etc/config-systests-ServerConfigurationTest-Old.xml b/qpid/java/systests/etc/config-systests-ServerConfigurationTest-Old.xml index e87be87154..56eaced9f7 100644 --- a/qpid/java/systests/etc/config-systests-ServerConfigurationTest-Old.xml +++ b/qpid/java/systests/etc/config-systests-ServerConfigurationTest-Old.xml @@ -56,9 +56,6 @@ </attributes> </principal-database> </principal-databases> -<jmx> -<principal-database>passwordfile</principal-database> -</jmx> </security> <virtualhosts>${conf}/virtualhosts-ServerConfigurationTest-New.xml <default>dev-only</default> diff --git a/qpid/java/systests/etc/config-systests-firewall-2.xml b/qpid/java/systests/etc/config-systests-firewall-2.xml index 05c3eaff9f..4c1bf9a800 100644 --- a/qpid/java/systests/etc/config-systests-firewall-2.xml +++ b/qpid/java/systests/etc/config-systests-firewall-2.xml @@ -84,10 +84,6 @@ <msg-auth>false</msg-auth> - <jmx> - <principal-database>passwordfile</principal-database> - </jmx> - <firewall default-action="deny"/> </security> diff --git a/qpid/java/systests/etc/config-systests-firewall-3.xml b/qpid/java/systests/etc/config-systests-firewall-3.xml index 861a3b33a3..19aaec9e54 100644 --- a/qpid/java/systests/etc/config-systests-firewall-3.xml +++ b/qpid/java/systests/etc/config-systests-firewall-3.xml @@ -84,10 +84,6 @@ <msg-auth>false</msg-auth> - <jmx> - <principal-database>passwordfile</principal-database> - </jmx> - <firewall default-action="deny"> <rule access="allow" network="127.0.0.1"/> </firewall> |