diff options
Diffstat (limited to 'java')
55 files changed, 1924 insertions, 1054 deletions
diff --git a/java/broker/etc/config.xml b/java/broker/etc/config.xml index ab6daef62d..da0d13b72f 100644 --- a/java/broker/etc/config.xml +++ b/java/broker/etc/config.xml @@ -49,73 +49,108 @@ <framesize>65535</framesize> <compressBufferOnQueue>false</compressBufferOnQueue> </advanced> - <security> - <principal-databases> - <principal-database> - <name>passwordfile</name> - <class>org.apache.qpid.server.security.auth.PasswordFilePrincipalDatabase</class> - <attributes> - <attribute> - <name>passwordFile</name> - <value>${conf}/passwd</value> - </attribute> - </attributes> - </principal-database> - </principal-databases> - <sasl> - <mechanisms> - <mechanism> - <initialiser> - <class>org.apache.qpid.server.security.auth.CRAMMD5Initialiser</class> - <principal-database>passwordfile</principal-database> - </initialiser> - </mechanism> - <mechanism> - <initialiser> - <class>org.apache.qpid.server.security.auth.amqplain.AmqPlainInitialiser</class> - <principal-database>passwordfile</principal-database> - </initialiser> - </mechanism> - <mechanism> - <initialiser> - <class>org.apache.qpid.server.security.auth.plain.PlainInitialiser</class> - <principal-database>passwordfile</principal-database> - </initialiser> - </mechanism> - </mechanisms> - </sasl> - </security> - <virtualhosts> - <virtualhost> - <name>localhost</name> - <localhost> - <store> - <!-- <class>org.apache.qpid.server.store.berkeleydb.BDBMessageStore</class> --> - <class>org.apache.qpid.server.store.MemoryMessageStore</class> - <environment-path>localhost-store</environment-path> - </store> - </localhost> - </virtualhost> - - <virtualhost> - <name>development</name> - <development> - <store> - <class>org.apache.qpid.server.store.MemoryMessageStore</class> - </store> - </development> - </virtualhost> - - <virtualhost> - <name>test</name> - <test> - <store> - <class>org.apache.qpid.server.store.MemoryMessageStore</class> - </store> - </test> - </virtualhost> - - </virtualhosts> + + <principal-databases> + <principal-database> + <name>passwordfile</name> + <class>org.apache.qpid.server.security.auth.database.PlainPasswordVhostFilePrincipalDatabase</class> + <attributes> + <attribute> + <name>passwordFile</name> + <value>${conf}/passwdVhost</value> + </attribute> + </attributes> + </principal-database> + + <principal-database> + <name>md5passwordfile</name> + <class>org.apache.qpid.server.security.auth.database.MD5PasswordFilePrincipalDatabase</class> + <attributes> + <attribute> + <name>passwordFile</name> + <value>${conf}/md5passwd</value> + </attribute> + </attributes> + </principal-database> + </principal-databases> + + <access> + <class>org.apache.qpid.server.security.access.AllowAll</class> + </access> + + <virtualhosts> + <virtualhost> + <name>localhost</name> + <localhost> + <store> + <!-- <class>org.apache.qpid.server.store.berkeleydb.BDBMessageStore</class> --> + <class>org.apache.qpid.server.store.MemoryMessageStore</class> + <environment-path>localhost-store</environment-path> + </store> + + <security> + <!-- Need protocol changes to allow this--> + <authentication> + <name>passwordfile</name> + <!-- Currently this can't be used as Vhost isn't specified at connection start only connection open --> + <mechanism>PLAIN</mechanism> + </authentication> + <access> + <class>org.apache.qpid.server.security.access.PrincipalDatabaseAccessManager</class> + <attributes> + <attribute> + <name>principalDatabase</name> + <value>passwordfile</value> + </attribute> + <attribute> + <name>defaultAccessManager</name> + <value>DenyAll</value> + </attribute> + </attributes> + </access> + </security> + </localhost> + </virtualhost> + + <virtualhost> + <name>development</name> + <development> + <store> + <class>org.apache.qpid.server.store.MemoryMessageStore</class> + </store> + <security> + <name>passwordfile-notusedyet</name> + <mechanism>PLAIN</mechanism> + <mechanism>CRAM-MD5</mechanism> + </security> + </development> + </virtualhost> + + <virtualhost> + <name>test</name> + <test> + <store> + <class>org.apache.qpid.server.store.MemoryMessageStore</class> + </store> + <security> + <name>passwordfile-notusedyet</name> + <mechanism>PLAIN</mechanism> + <mechanism>CRAM-MD5</mechanism> + </security> + <access> + <class>org.apache.qpid.server.security.access.PrincipalDatabaseAccessManager</class> + <attributes> + <attribute> + <name>principalDatabase</name> + <value>rubbish-to-cause-default</value> + </attribute> + </attributes> + </access> + + </test> + </virtualhost> + + </virtualhosts> <heartbeat> <delay>0</delay> <timeoutFactor>2.0</timeoutFactor> diff --git a/java/broker/etc/md5passwd b/java/broker/etc/md5passwd new file mode 100644 index 0000000000..f6839898bf --- /dev/null +++ b/java/broker/etc/md5passwd @@ -0,0 +1 @@ +guest:qfgyy4ewnVMBg diff --git a/java/broker/etc/passwdVhost b/java/broker/etc/passwdVhost new file mode 100644 index 0000000000..5db304e12c --- /dev/null +++ b/java/broker/etc/passwdVhost @@ -0,0 +1 @@ +guest:guest:localhost,test diff --git a/java/broker/etc/virtualhosts.xml b/java/broker/etc/virtualhosts.xml index c6dedd6433..f62ec3f5d7 100644 --- a/java/broker/etc/virtualhosts.xml +++ b/java/broker/etc/virtualhosts.xml @@ -23,7 +23,7 @@ <default>test</default> <virtualhost> <name>localhost</name> - <localhost> + <localhost> <exchanges> <exchange> <type>direct</type> diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java index a85af61327..2ecb39254f 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java @@ -7,9 +7,9 @@ * 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 @@ -32,9 +32,13 @@ import org.apache.qpid.server.state.AMQState; import org.apache.qpid.server.state.AMQStateManager; import org.apache.qpid.server.state.StateAwareMethodListener; import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.security.access.AccessResult; +import org.apache.log4j.Logger; public class ConnectionOpenMethodHandler implements StateAwareMethodListener<ConnectionOpenBody> { + private static final Logger _logger = Logger.getLogger(ConnectionOpenMethodHandler.class); + private static ConnectionOpenMethodHandler _instance = new ConnectionOpenMethodHandler(); public static ConnectionOpenMethodHandler getInstance() @@ -58,9 +62,9 @@ public class ConnectionOpenMethodHandler implements StateAwareMethodListener<Con //ignore leading '/' String virtualHostName; - if((body.virtualHost != null) && body.virtualHost.charAt(0) == '/') + if ((body.virtualHost != null) && body.virtualHost.charAt(0) == '/') { - virtualHostName = new StringBuilder(body.virtualHost.subSequence(1,body.virtualHost.length())).toString(); + virtualHostName = new StringBuilder(body.virtualHost.subSequence(1, body.virtualHost.length())).toString(); } else { @@ -69,15 +73,27 @@ public class ConnectionOpenMethodHandler implements StateAwareMethodListener<Con VirtualHost virtualHost = stateManager.getVirtualHostRegistry().getVirtualHost(virtualHostName); - if(virtualHost == null) + if (virtualHost == null) { throw body.getConnectionException(AMQConstant.NOT_FOUND, "Unknown virtual host: " + virtualHostName); } else { - session.setVirtualHost( virtualHost ); + session.setVirtualHost(virtualHost); + AccessResult result = virtualHost.getAccessManager().isAuthorized(virtualHost, session.getAuthorizedID()); + switch (result.getStatus()) + { + default: + case REFUSED: + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, + "Access denied to vHost '" + virtualHostName + "' by " + + result.getAuthorizer()); + case GRANTED: + _logger.info("Granted access to vHost '" + virtualHostName + "' for " + session.getAuthorizedID() + + " by '" + result.getAuthorizer() + "'"); + } // See Spec (0.8.2). Section 3.1.2 Virtual Hosts if (session.getContextKey() == null) @@ -88,9 +104,9 @@ public class ConnectionOpenMethodHandler implements StateAwareMethodListener<Con // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. // Be aware of possible changes to parameter order as versions change. - AMQFrame response = ConnectionOpenOkBody.createAMQFrame((short)0, - (byte)8, (byte)0, // AMQP version (major, minor) - body.virtualHost); + AMQFrame response = ConnectionOpenOkBody.createAMQFrame((short) 0, + (byte) 8, (byte) 0, // AMQP version (major, minor) + body.virtualHost); stateManager.changeState(AMQState.CONNECTION_OPEN); session.writeFrame(response); } diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java index 4ad6dcde71..6029a023e5 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java @@ -35,7 +35,7 @@ import org.apache.qpid.protocol.AMQMethodEvent; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.protocol.HeartbeatConfig; import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.security.auth.AuthenticationManager; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.security.auth.AuthenticationResult; import org.apache.qpid.server.state.AMQState; import org.apache.qpid.server.state.AMQStateManager; @@ -61,7 +61,10 @@ public class ConnectionSecureOkMethodHandler implements StateAwareMethodListener AMQProtocolSession session = stateManager.getProtocolSession(); ConnectionSecureOkBody body = evt.getMethod(); + //fixme Vhost not defined yet + //session.getVirtualHost().getAuthenticationManager(); AuthenticationManager authMgr = ApplicationRegistry.getInstance().getAuthenticationManager(); + SaslServer ss = session.getSaslServer(); if (ss == null) { @@ -103,6 +106,7 @@ public class ConnectionSecureOkMethodHandler implements StateAwareMethodListener ConnectionStartOkMethodHandler.getConfiguredFrameSize(), // frameMax HeartbeatConfig.getInstance().getDelay()); // heartbeat session.writeFrame(tune); + session.setAuthorizedID(ss.getAuthorizationID()); disposeSaslServer(session); break; case CONTINUE: diff --git a/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java index 65b79cf8e7..d8a20071b9 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java +++ b/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java @@ -31,10 +31,11 @@ import org.apache.qpid.framing.ConnectionSecureBody; import org.apache.qpid.framing.ConnectionStartOkBody; import org.apache.qpid.framing.ConnectionTuneBody; import org.apache.qpid.protocol.AMQMethodEvent; +import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.protocol.AMQProtocolSession; import org.apache.qpid.server.protocol.HeartbeatConfig; import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.security.auth.AuthenticationManager; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.security.auth.AuthenticationResult; import org.apache.qpid.server.state.AMQState; import org.apache.qpid.server.state.AMQStateManager; @@ -65,12 +66,18 @@ public class ConnectionStartOkMethodHandler implements StateAwareMethodListener< _logger.info("SASL Mechanism selected: " + body.mechanism); _logger.info("Locale selected: " + body.locale); - AuthenticationManager authMgr = ApplicationRegistry.getInstance().getAuthenticationManager(); + AuthenticationManager authMgr = ApplicationRegistry.getInstance().getAuthenticationManager();//session.getVirtualHost().getAuthenticationManager(); SaslServer ss = null; try { ss = authMgr.createSaslServer(String.valueOf(body.mechanism), session.getLocalFQDN()); + + if (ss == null) + { + throw body.getConnectionException(AMQConstant.RESOURCE_ERROR, "Unable to create SASL Server"); + } + session.setSaslServer(ss); AuthenticationResult authResult = authMgr.authenticate(ss, body.response); @@ -87,16 +94,17 @@ public class ConnectionStartOkMethodHandler implements StateAwareMethodListener< throw new AMQException("Authentication failed"); case SUCCESS: _logger.info("Connected as: " + ss.getAuthorizationID()); + session.setAuthorizedID(ss.getAuthorizationID()); stateManager.changeState(AMQState.CONNECTION_NOT_TUNED); // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. // Be aware of possible changes to parameter order as versions change. AMQFrame tune = ConnectionTuneBody.createAMQFrame(0, - (byte)8, (byte)0, // AMQP version (major, minor) - Integer.MAX_VALUE, // channelMax - getConfiguredFrameSize(), // frameMax - HeartbeatConfig.getInstance().getDelay()); // heartbeat + (byte) 8, (byte) 0, // AMQP version (major, minor) + Integer.MAX_VALUE, // channelMax + getConfiguredFrameSize(), // frameMax + HeartbeatConfig.getInstance().getDelay()); // heartbeat session.writeFrame(tune); break; case CONTINUE: @@ -105,8 +113,8 @@ public class ConnectionStartOkMethodHandler implements StateAwareMethodListener< // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. // Be aware of possible changes to parameter order as versions change. AMQFrame challenge = ConnectionSecureBody.createAMQFrame(0, - (byte)8, (byte)0, // AMQP version (major, minor) - authResult.challenge); // challenge + (byte) 8, (byte) 0, // AMQP version (major, minor) + authResult.challenge); // challenge session.writeFrame(challenge); } } diff --git a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index 133f4809b4..1c741ead1e 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -106,6 +106,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, private VersionSpecificRegistry _registry = MainRegistry.getVersionSpecificRegistry(_protocolVersion); private List<Integer> _closingChannelsList = new ArrayList<Integer>(); private ProtocolOutputConverter _protocolOutputConverter; + private String _authorizedID; public ManagedObject getManagedObject() @@ -205,22 +206,22 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, int channelId = frame.getChannel(); AMQBody body = frame.getBodyFrame(); - if(_logger.isDebugEnabled()) + if (_logger.isDebugEnabled()) { _logger.debug("Frame Received: " + frame); } if (body instanceof AMQMethodBody) { - methodFrameReceived(channelId, (AMQMethodBody)body); + methodFrameReceived(channelId, (AMQMethodBody) body); } else if (body instanceof ContentHeaderBody) { - contentHeaderReceived(channelId, (ContentHeaderBody)body); + contentHeaderReceived(channelId, (ContentHeaderBody) body); } else if (body instanceof ContentBody) { - contentBodyReceived(channelId, (ContentBody)body); + contentBodyReceived(channelId, (ContentBody) body); } else if (body instanceof HeartbeatBody) { @@ -674,7 +675,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, private void setProtocolVersion(byte major, byte minor) { - _protocolVersion = new ProtocolVersion(major,minor); + _protocolVersion = new ProtocolVersion(major, minor); _registry = MainRegistry.getVersionSpecificRegistry(_protocolVersion); @@ -735,5 +736,14 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, return _protocolOutputConverter; } + public void setAuthorizedID(String authorizedID) + { + _authorizedID = authorizedID; + } + + public String getAuthorizedID() + { + return _authorizedID; + } } diff --git a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java index 4cfee06850..79421dd497 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java +++ b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java @@ -165,4 +165,9 @@ public interface AMQProtocolSession extends AMQVersionAwareProtocolSession public ProtocolOutputConverter getProtocolOutputConverter(); + void setAuthorizedID(String authorizedID); + + /** @return a username string that was used to authorized this session */ + String getAuthorizedID(); + } diff --git a/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java index 70248a8e52..739ed9db42 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java +++ b/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java @@ -34,8 +34,12 @@ import org.apache.qpid.server.management.JMXManagedObjectRegistry; import org.apache.qpid.server.management.ManagedObjectRegistry; import org.apache.qpid.server.management.ManagementConfiguration; import org.apache.qpid.server.management.NoopManagedObjectRegistry; -import org.apache.qpid.server.security.auth.AuthenticationManager; -import org.apache.qpid.server.security.auth.SASLAuthenticationManager; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.security.auth.database.ConfigurationFilePrincipalDatabaseManager; +import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; +import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; +import org.apache.qpid.server.security.access.AccessManager; +import org.apache.qpid.server.security.access.AccessManagerImpl; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; @@ -46,6 +50,10 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry private AuthenticationManager _authenticationManager; + private AccessManager _accessManager; + + private PrincipalDatabaseManager _databaseManager; + private VirtualHostRegistry _virtualHostRegistry; @@ -59,26 +67,33 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry // Our configuration class needs to make the interpolate method // public so it can be called below from the config method. - private static class MyConfiguration extends CompositeConfiguration { - public String interpolate(String obj) { + private static class MyConfiguration extends CompositeConfiguration + { + public String interpolate(String obj) + { return super.interpolate(obj); } } - private static final Configuration config(File url) throws ConfigurationException { + private static final Configuration config(File url) throws ConfigurationException + { // We have to override the interpolate methods so that // interpolation takes place accross the entirety of the // composite configuration. Without doing this each // configuration object only interpolates variables defined // inside itself. final MyConfiguration conf = new MyConfiguration(); - conf.addConfiguration(new SystemConfiguration() { - protected String interpolate(String o) { + conf.addConfiguration(new SystemConfiguration() + { + protected String interpolate(String o) + { return conf.interpolate(o); } }); - conf.addConfiguration(new XMLConfiguration(url) { - protected String interpolate(String o) { + conf.addConfiguration(new XMLConfiguration(url) + { + protected String interpolate(String o) + { return conf.interpolate(o); } }); @@ -89,17 +104,22 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry { initialiseManagedObjectRegistry(); _virtualHostRegistry = new VirtualHostRegistry(); - _authenticationManager = new SASLAuthenticationManager(); + + _accessManager = new AccessManagerImpl("default", _configuration); + + _databaseManager = new ConfigurationFilePrincipalDatabaseManager(); + + _authenticationManager = new PrincipalDatabaseAuthenticationManager(null, null); initialiseVirtualHosts(); } private void initialiseVirtualHosts() throws Exception { - for(String name : getVirtualHostNames()) + for (String name : getVirtualHostNames()) { - - _virtualHostRegistry.registerVirtualHost(new VirtualHost(name,getConfiguration().subset("virtualhosts.virtualhost."+name))); + + _virtualHostRegistry.registerVirtualHost(new VirtualHost(name, getConfiguration().subset("virtualhosts.virtualhost." + name))); } } @@ -122,11 +142,21 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry return _virtualHostRegistry; } + public AccessManager getAccessManager() + { + return _accessManager; + } + public ManagedObjectRegistry getManagedObjectRegistry() { return _managedObjectRegistry; } + public PrincipalDatabaseManager getDatabaseManager() + { + return _databaseManager; + } + public AuthenticationManager getAuthenticationManager() { return _authenticationManager; @@ -134,6 +164,6 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry public Collection<String> getVirtualHostNames() { - return getConfiguration().getList("virtualhosts.virtualhost.name"); + return getConfiguration().getList("virtualhosts.virtualhost.name"); } } diff --git a/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java index 5924cdb178..5a48431288 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java +++ b/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java @@ -24,7 +24,9 @@ import java.util.Collection; import org.apache.commons.configuration.Configuration; import org.apache.qpid.server.management.ManagedObjectRegistry; -import org.apache.qpid.server.security.auth.AuthenticationManager; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; +import org.apache.qpid.server.security.access.AccessManager; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; public interface IApplicationRegistry @@ -57,9 +59,13 @@ public interface IApplicationRegistry ManagedObjectRegistry getManagedObjectRegistry(); + PrincipalDatabaseManager getDatabaseManager(); + AuthenticationManager getAuthenticationManager(); Collection<String> getVirtualHostNames(); VirtualHostRegistry getVirtualHostRegistry(); + + AccessManager getAccessManager(); } diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManager.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManager.java new file mode 100644 index 0000000000..0c0de88182 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManager.java @@ -0,0 +1,29 @@ +/* + * 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; + +public interface AccessManager +{ + AccessResult isAuthorized(Accessable accessObject, String username); + + String getName(); + +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManagerImpl.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManagerImpl.java new file mode 100644 index 0000000000..0b022aa8f7 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManagerImpl.java @@ -0,0 +1,136 @@ +/* + * 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; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.configuration.PropertyUtils; +import org.apache.qpid.configuration.PropertyException; +import org.apache.log4j.Logger; + +import java.util.List; +import java.lang.reflect.Method; +import java.lang.reflect.InvocationTargetException; + +public class AccessManagerImpl implements AccessManager +{ + private static final Logger _logger = Logger.getLogger(AccessManagerImpl.class); + + AccessManager _accessManager; + + public AccessManagerImpl(String name, Configuration hostConfig) throws ConfigurationException + { + String accessClass = hostConfig.getString("security.access.class"); + + if (accessClass == null) + { + _logger.warn("No access control specified. Using default access controls for VirtualHost:'" + name + "'"); + return; + } + + Object o; + try + { + o = Class.forName(accessClass).newInstance(); + } + catch (Exception e) + { + throw new ConfigurationException("Error initialising access control: " + e, e); + } + + if (!(o instanceof AccessManager)) + { + throw new ConfigurationException("Access control must implement the VirtualHostAccess interface"); + } + + initialiseAccessControl((AccessManager) o, hostConfig); + + _accessManager = (AccessManager) o; + + _logger.info("Initialised access control for virtualhost '" + name + "' successfully"); + + } + + + private void initialiseAccessControl(AccessManager accessManager, Configuration config) + throws ConfigurationException + { + String baseName = "access.attributes.attribute."; + List<String> argumentNames = config.getList(baseName + "name"); + List<String> argumentValues = config.getList(baseName + "value"); + for (int i = 0; i < argumentNames.size(); i++) + { + String argName = argumentNames.get(i); + if (argName == null || argName.length() == 0) + { + throw new ConfigurationException("Access Control argument names must have length >= 1 character"); + } + if (Character.isLowerCase(argName.charAt(0))) + { + argName = Character.toUpperCase(argName.charAt(0)) + argName.substring(1); + } + String methodName = "set" + argName; + Method method = null; + try + { + method = accessManager.getClass().getMethod(methodName, String.class); + } + catch (NoSuchMethodException e) + { + //do nothing as method will be null + } + + if (method == null) + { + throw new ConfigurationException("No method " + methodName + " found in class " + accessManager.getClass() + + " hence unable to configure access control. The method must be public and " + + "have a single String argument with a void return type"); + } + try + { + method.invoke(accessManager, PropertyUtils.replaceProperties(argumentValues.get(i))); + } + catch (Exception e) + { + throw new ConfigurationException(e.getCause()); + } + } + } + + + public AccessResult isAuthorized(Accessable accessObject, String username) + { + if (_accessManager == null) + { + return ApplicationRegistry.getInstance().getAccessManager().isAuthorized(accessObject, username); + } + else + { + return _accessManager.isAuthorized(accessObject, username); + } + } + + public String getName() + { + return "AccessManagerImpl"; + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java new file mode 100644 index 0000000000..b8d8fc605a --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessResult.java @@ -0,0 +1,66 @@ +/* + * 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; + +public class AccessResult +{ + public enum AccessStatus + { + GRANTED, REFUSED + } + + StringBuilder _authorizer; + AccessStatus _status; + + public AccessResult(AccessManager authorizer, AccessStatus status) + { + _status = status; + _authorizer = new StringBuilder(authorizer.getName()); + } + + public void setAuthorizer(AccessManager authorizer) + { + _authorizer.append(authorizer.getName()); + } + + public String getAuthorizer() + { + return _authorizer.toString(); + } + + public void setStatus(AccessStatus status) + { + _status = status; + } + + public AccessStatus getStatus() + { + return _status; + } + + public void addAuthorizer(AccessManager accessManager) + { + _authorizer.insert(0, "->"); + _authorizer.insert(0, accessManager.getName()); + } + + +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/Accessable.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/Accessable.java new file mode 100644 index 0000000000..f51cf24caa --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/Accessable.java @@ -0,0 +1,27 @@ +/* + * 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; + +public interface Accessable +{ + void setAccessableName(String name); + String getAccessableName(); +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/AllowAll.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/AllowAll.java new file mode 100644 index 0000000000..b2e4094edd --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/AllowAll.java @@ -0,0 +1,35 @@ +/* + * 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; + +public class AllowAll implements AccessManager +{ + + public AccessResult isAuthorized(Accessable accessObject, String username) + { + return new AccessResult(this, AccessResult.AccessStatus.GRANTED); + } + + public String getName() + { + return "AllowAll"; + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/DenyAll.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/DenyAll.java new file mode 100644 index 0000000000..0e62d2657f --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/DenyAll.java @@ -0,0 +1,34 @@ +/* + * 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; + +public class DenyAll implements AccessManager +{ + public AccessResult isAuthorized(Accessable accessObject, String username) + { + return new AccessResult(this, AccessResult.AccessStatus.REFUSED); + } + + public String getName() + { + return "DenyAll"; + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalDatabaseAccessManager.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalDatabaseAccessManager.java new file mode 100644 index 0000000000..d41e5dfb94 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalDatabaseAccessManager.java @@ -0,0 +1,84 @@ +/* + * 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; + +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.log4j.Logger; + +public class PrincipalDatabaseAccessManager implements AccessManager +{ + private static final Logger _logger = Logger.getLogger(PrincipalDatabaseAccessManager.class); + + PrincipalDatabase _database; + AccessManager _default; + + public PrincipalDatabaseAccessManager() + { + _default = ApplicationRegistry.getInstance().getAccessManager(); + } + + public void setDefaultAccessManager(String defaultAM) + { + if (defaultAM.equals("AllowAll")) + { + _default = new AllowAll(); + } + + if (defaultAM.equals("DenyAll")) + { + _default = new DenyAll(); + } + } + + public void setPrincipalDatabase(String database) + { + _database = ApplicationRegistry.getInstance().getDatabaseManager().getDatabases().get(database); + if (!(_database instanceof AccessManager)) + { + _logger.warn("Database '" + database + "' cannot perform access management"); + } + } + + public AccessResult isAuthorized(Accessable accessObject, String username) + { + AccessResult result; + + if (_database == null) + { + result = _default.isAuthorized(accessObject, username); + } + else + { + result = ((AccessManager) _database).isAuthorized(accessObject, username); + } + + result.addAuthorizer(this); + + return result; + } + + public String getName() + { + return "PrincipalDatabaseFileAccessManager"; + } + +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/NullAuthenticationManager.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/NullAuthenticationManager.java deleted file mode 100644 index 20f190876f..0000000000 --- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/NullAuthenticationManager.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth; - -import javax.security.sasl.SaslException; -import javax.security.sasl.SaslServer; - -public class NullAuthenticationManager implements AuthenticationManager -{ - public String getMechanisms() - { - return "PLAIN"; - } - - public SaslServer createSaslServer(String mechanism, String localFQDN) throws SaslException - { - return new SaslServer() - { - public String getMechanismName() - { - return "PLAIN"; - } - - public byte[] evaluateResponse(byte[] response) throws SaslException - { - return new byte[0]; - } - - public boolean isComplete() - { - return true; - } - - public String getAuthorizationID() - { - return "guest"; - } - - public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException - { - return new byte[0]; - } - - public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException - { - return new byte[0]; - } - - public Object getNegotiatedProperty(String propName) - { - return null; - } - - public void dispose() throws SaslException - { - } - }; - } - - public AuthenticationResult authenticate(SaslServer server, byte[] response) - { - return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.SUCCESS); - } -} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/SASLAuthenticationManager.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/SASLAuthenticationManager.java deleted file mode 100644 index 66923e371b..0000000000 --- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/SASLAuthenticationManager.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth; - -import java.lang.reflect.Method; -import java.security.Security; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; - -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 org.apache.commons.configuration.Configuration; -import org.apache.log4j.Logger; -import org.apache.qpid.configuration.PropertyUtils; -import org.apache.qpid.server.registry.ApplicationRegistry; - -public class SASLAuthenticationManager implements AuthenticationManager -{ - private static final Logger _log = Logger.getLogger(SASLAuthenticationManager.class); - - /** - * The list of mechanisms, in the order in which they are configured (i.e. preferred order) - */ - private String _mechanisms; - - /** - * Maps from the mechanism to the callback handler to use for handling those requests - */ - private Map<String, CallbackHandler> _callbackHandlerMap = new HashMap<String, CallbackHandler>(); - - /** - * Maps from the mechanism to the properties used to initialise the server. See the method - * Sasl.createSaslServer for details of the use of these properties. This map is populated during initialisation - * of each provider. - */ - private Map<String, Map<String, ?>> _serverCreationProperties = new HashMap<String, Map<String, ?>>(); - - public SASLAuthenticationManager() throws Exception - { - _log.info("Initialising SASL authentication manager"); - Map<String, PrincipalDatabase> databases = initialisePrincipalDatabases(); - initialiseAuthenticationMechanisms(databases); - } - - private Map<String, PrincipalDatabase> initialisePrincipalDatabases() throws Exception - { - Configuration config = ApplicationRegistry.getInstance().getConfiguration(); - List<String> databaseNames = config.getList("security.principal-databases.principal-database.name"); - List<String> databaseClasses = config.getList("security.principal-databases.principal-database.class"); - Map<String, PrincipalDatabase> databases = new HashMap<String, PrincipalDatabase>(); - for (int i = 0; i < databaseNames.size(); i++) - { - Object o; - try - { - o = Class.forName(databaseClasses.get(i)).newInstance(); - } - catch (Exception e) - { - throw new Exception("Error initialising principal database: " + e, e); - } - - if (!(o instanceof PrincipalDatabase)) - { - throw new Exception("Principal databases must implement the PrincipalDatabase interface"); - } - - initialisePrincipalDatabase((PrincipalDatabase) o, config, i); - - String name = databaseNames.get(i); - if (name == null || name.length() == 0) - { - throw new Exception("Principal database names must have length greater than or equal to one character"); - } - PrincipalDatabase pd = databases.get(name); - if (pd != null) - { - throw new Exception("Duplicate principal database name provided"); - } - _log.info("Initialised principal database " + name + " successfully"); - databases.put(name, (PrincipalDatabase) o); - } - return databases; - } - - private void initialisePrincipalDatabase(PrincipalDatabase principalDatabase, Configuration config, int index) - throws Exception - { - String baseName = "security.principal-databases.principal-database(" + index + ").attributes.attribute."; - List<String> argumentNames = config.getList(baseName + "name"); - List<String> argumentValues = config.getList(baseName + "value"); - for (int i = 0; i < argumentNames.size(); i++) - { - String argName = argumentNames.get(i); - if (argName == null || argName.length() == 0) - { - throw new Exception("Argument names must have length >= 1 character"); - } - if (Character.isLowerCase(argName.charAt(0))) - { - argName = Character.toUpperCase(argName.charAt(0)) + argName.substring(1); - } - String methodName = "set" + argName; - Method method = principalDatabase.getClass().getMethod(methodName, String.class); - if (method == null) - { - throw new Exception("No method " + methodName + " found in class " + principalDatabase.getClass() + - " hence unable to configure principal database. The method must be public and " + - "have a single String argument with a void return type"); - } - method.invoke(principalDatabase, PropertyUtils.replaceProperties(argumentValues.get(i))); - } - } - - private void initialiseAuthenticationMechanisms(Map<String, PrincipalDatabase> databases) throws Exception - { - Configuration config = ApplicationRegistry.getInstance().getConfiguration(); - List<String> mechanisms = config.getList("security.sasl.mechanisms.mechanism.initialiser.class"); - - // Maps from the mechanism to the properties used to initialise the server. See the method - // Sasl.createSaslServer for details of the use of these properties. This map is populated during initialisation - // of each provider. - Map<String, Class<? extends SaslServerFactory>> providerMap = new TreeMap<String, Class<? extends SaslServerFactory>>(); - - for (int i = 0; i < mechanisms.size(); i++) - { - String baseName = "security.sasl.mechanisms.mechanism(" + i + ").initialiser"; - String clazz = config.getString(baseName + ".class"); - initialiseAuthenticationMechanism(baseName, clazz, databases, config, providerMap); - } - if (providerMap.size() > 0) - { - Security.addProvider(new JCAProvider(providerMap)); - } - } - - private void initialiseAuthenticationMechanism(String baseName, String clazz, - Map<String, PrincipalDatabase> databases, - Configuration configuration, - Map<String, Class<? extends SaslServerFactory>> providerMap) - throws Exception - { - Class initialiserClazz = Class.forName(clazz); - Object o = initialiserClazz.newInstance(); - if (!(o instanceof AuthenticationProviderInitialiser)) - { - throw new Exception("The class " + clazz + " must be an instance of " + - AuthenticationProviderInitialiser.class); - } - AuthenticationProviderInitialiser initialiser = (AuthenticationProviderInitialiser) o; - initialiser.initialise(baseName, configuration, databases); - String mechanism = initialiser.getMechanismName(); - if (_mechanisms == null) - { - _mechanisms = mechanism; - } - else - { - // simple append should be fine since the number of mechanisms is small and this is a one time initialisation - _mechanisms = _mechanisms + " " + mechanism; - } - _callbackHandlerMap.put(mechanism, initialiser.getCallbackHandler()); - _serverCreationProperties.put(mechanism, initialiser.getProperties()); - Class<? extends SaslServerFactory> factory = initialiser.getServerFactoryClassForJCARegistration(); - if (factory != null) - { - providerMap.put(mechanism, factory); - } - _log.info("Initialised " + mechanism + " SASL provider successfully"); - } - - public String getMechanisms() - { - return _mechanisms; - } - - public SaslServer createSaslServer(String mechanism, String localFQDN) throws SaslException - { - return Sasl.createSaslServer(mechanism, "AMQP", localFQDN, _serverCreationProperties.get(mechanism), - _callbackHandlerMap.get(mechanism)); - } - - public AuthenticationResult authenticate(SaslServer server, byte[] response) - { - try - { - // Process response from the client - byte[] challenge = server.evaluateResponse(response != null ? response : new byte[0]); - - if (server.isComplete()) - { - return new AuthenticationResult(challenge, AuthenticationResult.AuthenticationStatus.SUCCESS); - } - else - { - return new AuthenticationResult(challenge, AuthenticationResult.AuthenticationStatus.CONTINUE); - } - } - catch (SaslException e) - { - return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR); - } - } -} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainInitialiser.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainInitialiser.java deleted file mode 100644 index 543115fd90..0000000000 --- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainInitialiser.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.amqplain; - -import javax.security.sasl.SaslServerFactory; - -import org.apache.qpid.server.security.auth.UsernamePasswordInitialiser; - -public class AmqPlainInitialiser extends UsernamePasswordInitialiser -{ - public String getMechanismName() - { - return "AMQPLAIN"; - } - - public Class<? extends SaslServerFactory> getServerFactoryClassForJCARegistration() - { - return AmqPlainSaslServerFactory.class; - } -} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServer.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServer.java deleted file mode 100644 index 9e5a8f9a08..0000000000 --- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServer.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.amqplain; - -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 org.apache.mina.common.ByteBuffer; -import org.apache.qpid.framing.AMQFrameDecodingException; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.FieldTableFactory; - -public class AmqPlainSaslServer implements SaslServer -{ - public static final String MECHANISM = "AMQPLAIN"; - - private CallbackHandler _cbh; - - private String _authorizationId; - - private boolean _complete = false; - - public AmqPlainSaslServer(CallbackHandler cbh) - { - _cbh = cbh; - } - - public String getMechanismName() - { - return MECHANISM; - } - - public byte[] evaluateResponse(byte[] response) throws SaslException - { - try - { - final FieldTable ft = FieldTableFactory.newFieldTable(ByteBuffer.wrap(response), response.length); - String username = (String) ft.getString("LOGIN"); - // we do not care about the prompt but it throws if null - NameCallback nameCb = new NameCallback("prompt", username); - // we do not care about the prompt but it throws if null - PasswordCallback passwordCb = new PasswordCallback("prompt", false); - // TODO: should not get pwd as a String but as a char array... - String pwd = (String) ft.getString("PASSWORD"); - passwordCb.setPassword(pwd.toCharArray()); - AuthorizeCallback authzCb = new AuthorizeCallback(username, username); - Callback[] callbacks = new Callback[]{nameCb, passwordCb, authzCb}; - _cbh.handle(callbacks); - _complete = true; - if (authzCb.isAuthorized()) - { - _authorizationId = authzCb.getAuthenticationID(); - return null; - } - else - { - throw new SaslException("Authentication failed"); - } - } - catch (AMQFrameDecodingException e) - { - throw new SaslException("Unable to decode response: " + e, e); - } - catch (IOException e) - { - throw new SaslException("Error processing data: " + e, e); - } - catch (UnsupportedCallbackException e) - { - throw new SaslException("Unable to obtain data from callback handler: " + e, e); - } - } - - public boolean isComplete() - { - return _complete; - } - - public String getAuthorizationID() - { - return _authorizationId; - } - - public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException - { - throw new SaslException("Unsupported operation"); - } - - public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException - { - throw new SaslException("Unsupported operation"); - } - - public Object getNegotiatedProperty(String propName) - { - return null; - } - - public void dispose() throws SaslException - { - _cbh = null; - } -} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServerFactory.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServerFactory.java deleted file mode 100644 index 2569314a4a..0000000000 --- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/AmqPlainSaslServerFactory.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.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; - -public class AmqPlainSaslServerFactory implements SaslServerFactory -{ - public SaslServer createSaslServer(String mechanism, String protocol, String serverName, Map props, - CallbackHandler cbh) throws SaslException - { - if (AmqPlainSaslServer.MECHANISM.equals(mechanism)) - { - return new AmqPlainSaslServer(cbh); - } - else - { - return null; - } - } - - public String[] getMechanismNames(Map props) - { - if (props.containsKey(Sasl.POLICY_NOPLAINTEXT) || - props.containsKey(Sasl.POLICY_NODICTIONARY) || - props.containsKey(Sasl.POLICY_NOACTIVE)) - { - // returned array must be non null according to interface documentation - return new String[0]; - } - else - { - return new String[]{AmqPlainSaslServer.MECHANISM}; - } - } -} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java new file mode 100644 index 0000000000..dde4ce7c4d --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java @@ -0,0 +1,148 @@ +/* + * 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.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.configuration.PropertyUtils; +import org.apache.log4j.Logger; + +import java.util.Map; +import java.util.List; +import java.util.HashMap; +import java.lang.reflect.Method; +import java.io.FileNotFoundException; + +public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatabaseManager +{ + private static final Logger _logger = Logger.getLogger(ConfigurationFilePrincipalDatabaseManager.class); + + private static final String _base = "principal-databases.principal-database"; + + Map<String, PrincipalDatabase> _databases; + + public ConfigurationFilePrincipalDatabaseManager() throws Exception + { + _logger.info("Initialising PrincipleDatabase authentication manager"); + _databases = initialisePrincipalDatabases(); + } + + private Map<String, PrincipalDatabase> initialisePrincipalDatabases() throws Exception + { + Configuration config = ApplicationRegistry.getInstance().getConfiguration(); + List<String> databaseNames = config.getList(_base + ".name"); + List<String> databaseClasses = config.getList(_base + ".class"); + Map<String, PrincipalDatabase> databases = new HashMap<String, PrincipalDatabase>(); + + if (databaseNames.size() == 0) + { + _logger.warn("No Principal databases specified. Broker running with NO AUTHENTICATION"); + } + + for (int i = 0; i < databaseNames.size(); i++) + { + Object o; + try + { + o = Class.forName(databaseClasses.get(i)).newInstance(); + } + catch (Exception e) + { + throw new Exception("Error initialising principal database: " + e, e); + } + + if (!(o instanceof PrincipalDatabase)) + { + throw new Exception("Principal databases must implement the PrincipalDatabase interface"); + } + + initialisePrincipalDatabase((PrincipalDatabase) o, config, i); + + String name = databaseNames.get(i); + if (name == null || name.length() == 0) + { + throw new Exception("Principal database names must have length greater than or equal to one character"); + } + PrincipalDatabase pd = databases.get(name); + if (pd != null) + { + throw new Exception("Duplicate principal database name not provided"); + } + _logger.info("Initialised principal database '" + name + "' successfully"); + databases.put(name, (PrincipalDatabase) o); + } + return databases; + } + + private void initialisePrincipalDatabase(PrincipalDatabase principalDatabase, Configuration config, int index) + throws FileNotFoundException, ConfigurationException + { + String baseName = _base + "(" + index + ").attributes.attribute."; + List<String> argumentNames = config.getList(baseName + "name"); + List<String> argumentValues = config.getList(baseName + "value"); + for (int i = 0; i < argumentNames.size(); i++) + { + String argName = argumentNames.get(i); + if (argName == null || argName.length() == 0) + { + throw new ConfigurationException("Argument names must have length >= 1 character"); + } + if (Character.isLowerCase(argName.charAt(0))) + { + argName = Character.toUpperCase(argName.charAt(0)) + argName.substring(1); + } + String methodName = "set" + argName; + Method method = null; + try + { + method = principalDatabase.getClass().getMethod(methodName, String.class); + } + catch (Exception e) + { + // do nothing.. as on error method will be null + } + + if (method == null) + { + throw new ConfigurationException("No method " + methodName + " found in class " + principalDatabase.getClass() + + " hence unable to configure principal database. The method must be public and " + + "have a single String argument with a void return type"); + } + + try + { + method.invoke(principalDatabase, PropertyUtils.replaceProperties(argumentValues.get(i))); + } + catch (Exception ite) + { + throw new ConfigurationException(ite.getCause()); + } + } + } + + public Map<String, PrincipalDatabase> getDatabases() + { + return _databases; + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/PasswordFilePrincipalDatabase.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/MD5PasswordFilePrincipalDatabase.java index b0592a7173..98fca99aa3 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/PasswordFilePrincipalDatabase.java +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/MD5PasswordFilePrincipalDatabase.java @@ -1,61 +1,77 @@ /* + * 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 * - * 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. + * 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; +package org.apache.qpid.server.security.auth.database; -import java.io.BufferedReader; +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.crammd5.CRAMMD5Initialiser; +import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser; + +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.login.AccountNotFoundException; import java.io.File; import java.io.FileNotFoundException; -import java.io.FileReader; import java.io.IOException; -import java.security.Principal; +import java.io.BufferedReader; +import java.io.FileReader; import java.util.regex.Pattern; - -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.login.AccountNotFoundException; - -import org.apache.log4j.Logger; +import java.util.Map; +import java.util.HashMap; +import java.security.Principal; /** * Represents a user database where the account information is stored in a simple flat file. * - * The file is expected to be in the form: - * username:password - * username1:password1 - * ... - * usernamen:passwordn - * - * where a carriage return separates each username/password pair. Passwords are assumed to be in - * plain text. + * The file is expected to be in the form: username:password username1:password1 ... usernamen:passwordn * + * where a carriage return separates each username/password pair. Passwords are assumed to be in plain text. */ -public class PasswordFilePrincipalDatabase implements PrincipalDatabase +public class MD5PasswordFilePrincipalDatabase implements PrincipalDatabase { - private static final Logger _logger = Logger.getLogger(PasswordFilePrincipalDatabase.class); + private static final Logger _logger = Logger.getLogger(MD5PasswordFilePrincipalDatabase.class); private File _passwordFile; private Pattern _regexp = Pattern.compile(":"); - public PasswordFilePrincipalDatabase() + private Map<String, AuthenticationProviderInitialiser> _saslServers; + + public MD5PasswordFilePrincipalDatabase() { + _saslServers = new HashMap<String, AuthenticationProviderInitialiser>(); + + /** + * Create Authenticators for MD5 Password file. + */ + + // Accept MD5 incomming and use plain comparison with the file + PlainInitialiser cram = new PlainInitialiser(); + cram.initialise(this); + // Accept Plain incomming and hash it for comparison to the file. + CRAMMD5Initialiser plain = new CRAMMD5Initialiser(); + plain.initialise(this,CRAMMD5Initialiser.HashDirection.INCOMMING); + + _saslServers.put(plain.getMechanismName(), cram); + _saslServers.put(cram.getMechanismName(), plain); } public void setPasswordFile(String passwordFile) throws FileNotFoundException @@ -75,7 +91,7 @@ public class PasswordFilePrincipalDatabase implements PrincipalDatabase } public void setPassword(Principal principal, PasswordCallback callback) throws IOException, - AccountNotFoundException + AccountNotFoundException { if (_passwordFile == null) { @@ -96,13 +112,20 @@ public class PasswordFilePrincipalDatabase implements PrincipalDatabase } } + public Map<String, AuthenticationProviderInitialiser> getMechanisms() + { + return _saslServers; + } + /** - * 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. + * 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 + * * @return - * @throws IOException + * + * @throws java.io.IOException */ private char[] lookupPassword(String name) throws IOException { diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java new file mode 100644 index 0000000000..6770baaece --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java @@ -0,0 +1,163 @@ +/* + * 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.database.PrincipalDatabase; +import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; +import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5Initialiser; +import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser; + +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.login.AccountNotFoundException; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.BufferedReader; +import java.io.FileReader; +import java.util.regex.Pattern; +import java.util.Map; +import java.util.HashMap; +import java.security.Principal; + +/** + * Represents a user database where the account information is stored in a simple flat file. + * + * The file is expected to be in the form: username:password username1:password1 ... usernamen:passwordn + * + * where a carriage return separates each username/password pair. Passwords are assumed to be in plain text. + */ +public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase +{ + private static final Logger _logger = Logger.getLogger(PlainPasswordFilePrincipalDatabase.class); + + private File _passwordFile; + + private Pattern _regexp = Pattern.compile(":"); + + private Map<String, AuthenticationProviderInitialiser> _saslServers; + + public PlainPasswordFilePrincipalDatabase() + { + _saslServers = new HashMap<String, AuthenticationProviderInitialiser>(); + + /** + * Create Authenticators for Plain Password file. + */ + + // 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(plain.getMechanismName(), plain); + _saslServers.put(cram.getMechanismName(), cram); + } + + public void setPasswordFile(String passwordFile) throws FileNotFoundException + { + 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."); + } + } + + public void setPassword(Principal principal, PasswordCallback callback) throws IOException, + 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); + } + } + + public Map<String, AuthenticationProviderInitialiser> getMechanisms() + { + return _saslServers; + } + + + /** + * 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 + * + * @return + * + * @throws java.io.IOException + */ + private char[] lookupPassword(String name) throws IOException + { + 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) + { + continue; + } + + if (name.equals(result[0])) + { + return result[1].toCharArray(); + } + } + return null; + } + finally + { + if (reader != null) + { + reader.close(); + } + } + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java new file mode 100644 index 0000000000..37d883769a --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java @@ -0,0 +1,241 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.auth.database; + +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; +import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5Initialiser; +import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser; +import org.apache.qpid.server.security.access.AccessManager; +import org.apache.qpid.server.security.access.AccessResult; +import org.apache.qpid.server.security.access.Accessable; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.log4j.Logger; + +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.login.AccountNotFoundException; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.BufferedReader; +import java.io.FileReader; +import java.util.regex.Pattern; +import java.util.Map; +import java.util.HashMap; +import java.security.Principal; + +/** + * Represents a user database where the account information is stored in a simple flat file. + * + * The file is expected to be in the form: username:password username1:password1 ... usernamen:passwordn + * + * where a carriage return separates each username/password pair. Passwords are assumed to be in plain text. + */ +public class PlainPasswordVhostFilePrincipalDatabase implements PrincipalDatabase, AccessManager +{ + private static final Logger _logger = Logger.getLogger(PlainPasswordVhostFilePrincipalDatabase.class); + + private File _passwordFile; + + private Pattern _regexp = Pattern.compile(":"); + + private Map<String, AuthenticationProviderInitialiser> _saslServers; + + public PlainPasswordVhostFilePrincipalDatabase() + { + _saslServers = new HashMap<String, AuthenticationProviderInitialiser>(); + + /** + * Create Authenticators for Plain Password file. + */ + + // 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(plain.getMechanismName(), plain); + _saslServers.put(cram.getMechanismName(), cram); + } + + public void setPasswordFile(String passwordFile) throws FileNotFoundException + { + 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."); + } + } + + public void setPassword(Principal principal, PasswordCallback callback) throws IOException, + 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); + } + } + + public Map<String, AuthenticationProviderInitialiser> getMechanisms() + { + return _saslServers; + } + + + /** + * 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 + * + * @return + * + * @throws java.io.IOException + */ + private char[] lookupPassword(String name) throws IOException + { + 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) + { + continue; + } + + if (name.equals(result[0])) + { + return result[1].toCharArray(); + } + } + return null; + } + finally + { + if (reader != null) + { + reader.close(); + } + } + } + + /** + * Looks up the virtual hosts for a specified user in the password file. + * + * @param user The user to lookup + * + * @return a list of virtualhosts + */ + private String[] lookupVirtualHost(String user) + { + try + { + 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 < 3) + { + continue; + } + + if (user.equals(result[0])) + { + return result[2].split(","); + } + } + return null; + } + finally + { + if (reader != null) + { + reader.close(); + } + } + } + catch (IOException ioe) + { + //ignore + } + return null; + } + + + public AccessResult isAuthorized(Accessable accessObject, String username) + { + if (accessObject instanceof VirtualHost) + { + String[] hosts = lookupVirtualHost(username); + + if (hosts != null) + { + for (String host : hosts) + { + if (accessObject.getAccessableName().equals(host)) + { + return new AccessResult(this, AccessResult.AccessStatus.GRANTED); + } + } + } + } + + return new AccessResult(this, AccessResult.AccessStatus.REFUSED); + } + + public String getName() + { + return "PlainPasswordVhostFile"; + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/PrincipalDatabase.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java index e731ea271b..6c5a2a44ee 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/PrincipalDatabase.java +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java @@ -18,29 +18,33 @@ * under the License. * */ -package org.apache.qpid.server.security.auth; +package org.apache.qpid.server.security.auth.database; + +import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; import java.io.IOException; import java.security.Principal; +import java.util.Map; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.login.AccountNotFoundException; -/** - * Represents a "user database" which is really a way of storing principals (i.e. usernames) and - * passwords. - */ +/** Represents a "user database" which is really a way of storing principals (i.e. usernames) and passwords. */ public interface PrincipalDatabase { /** - * Set the password for a given principal in the specified callback. This is used for certain - * SASL providers. The user database implementation should look up the password in any way it - * chooses and set it in the callback by calling its setPassword method. + * Set the password for a given principal in the specified callback. This is used for certain SASL providers. The + * user database implementation should look up the password in any way it chooses and set it in the callback by + * calling its setPassword method. + * * @param principal the principal - * @param callback the password callback that wants to receive the password + * @param callback the password callback that wants to receive the password + * * @throws AccountNotFoundException if the account for specified principal could not be found - * @throws IOException if there was an error looking up the principal + * @throws IOException if there was an error looking up the principal */ void setPassword(Principal principal, PasswordCallback callback) throws IOException, AccountNotFoundException; + + public Map<String, AuthenticationProviderInitialiser> getMechanisms(); } diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java new file mode 100644 index 0000000000..83f1201bd8 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.auth.database; + +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; + +import java.util.Map; + +public interface PrincipalDatabaseManager +{ + public Map<String, PrincipalDatabase> getDatabases(); +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java new file mode 100644 index 0000000000..9a58acd98c --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.auth.database; + +import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; +import org.apache.qpid.server.security.auth.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.util.Properties; +import java.util.Map; +import java.util.HashMap; +import java.security.Principal; +import java.io.IOException; + +public class PropertiesPrincipalDatabase implements PrincipalDatabase +{ + private Properties _users; + + private Map<String, AuthenticationProviderInitialiser> _saslServers; + + public PropertiesPrincipalDatabase(Properties users) + { + _users = users; + + _saslServers = new HashMap<String, AuthenticationProviderInitialiser>(); + + /** + * Create Authenticators for Properties Principal Database. + */ + + // Accept MD5 incomming and use plain comparison with the file + PlainInitialiser cram = new PlainInitialiser(); + cram.initialise(this); + // Accept Plain incomming and hash it for comparison to the file. + CRAMMD5Initialiser plain = new CRAMMD5Initialiser(); + plain.initialise(this, CRAMMD5Initialiser.HashDirection.INCOMMING); + + _saslServers.put(plain.getMechanismName(), cram); + _saslServers.put(cram.getMechanismName(), plain); + } + + public void setPassword(Principal principal, PasswordCallback callback) throws IOException, AccountNotFoundException + { + if (principal == null) + { + throw new IllegalArgumentException("principal must not be null"); + } + char[] pwd = _users.getProperty(principal.getName()).toCharArray(); + if (pwd != null) + { + callback.setPassword(pwd); + } + else + { + throw new AccountNotFoundException("No account found for principal " + principal); + } + } + + public Map<String, AuthenticationProviderInitialiser> getMechanisms() + { + return _saslServers; + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java new file mode 100644 index 0000000000..89c84e8130 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java @@ -0,0 +1,41 @@ +/* + * 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.util.Map; +import java.util.Properties; +import java.util.HashMap; + +public class PropertiesPrincipalDatabaseManager implements PrincipalDatabaseManager +{ + + Map<String, PrincipalDatabase> _databases = new HashMap<String, PrincipalDatabase>(); + + public PropertiesPrincipalDatabaseManager(String name, Properties users) + { + _databases.put(name, new PropertiesPrincipalDatabase(users)); + } + + public Map<String, PrincipalDatabase> getDatabases() + { + return _databases; + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationManager.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java index 9f4addd7ee..bb94e0b7bf 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationManager.java +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java @@ -18,7 +18,10 @@ * under the License. * */ -package org.apache.qpid.server.security.auth; +package org.apache.qpid.server.security.auth.manager; + +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.security.auth.AuthenticationResult; import javax.security.sasl.SaslException; import javax.security.sasl.SaslServer; @@ -30,4 +33,5 @@ public interface AuthenticationManager SaslServer createSaslServer(String mechanism, String localFQDN) throws SaslException; AuthenticationResult authenticate(SaslServer server, byte[] response); + } diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java new file mode 100644 index 0000000000..d0862fbb63 --- /dev/null +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java @@ -0,0 +1,246 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.auth.manager; + +import org.apache.log4j.Logger; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.SubsetConfiguration; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +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.AuthenticationResult; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.SaslServerFactory; +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslException; +import javax.security.sasl.Sasl; +import java.util.Map; +import java.util.HashMap; +import java.util.TreeMap; +import java.security.Security; + +public class PrincipalDatabaseAuthenticationManager implements AuthenticationManager +{ + private static final Logger _logger = Logger.getLogger(PrincipalDatabaseAuthenticationManager.class); + + /** The list of mechanisms, in the order in which they are configured (i.e. preferred order) */ + private String _mechanisms; + + /** Maps from the mechanism to the callback handler to use for handling those requests */ + private Map<String, CallbackHandler> _callbackHandlerMap = new HashMap<String, CallbackHandler>(); + + /** + * Maps from the mechanism to the properties used to initialise the server. See the method Sasl.createSaslServer for + * details of the use of these properties. This map is populated during initialisation of each provider. + */ + private Map<String, Map<String, ?>> _serverCreationProperties = new HashMap<String, Map<String, ?>>(); + + private AuthenticationManager _default = null; + + public PrincipalDatabaseAuthenticationManager(String name, Configuration hostConfig) throws Exception + { + _logger.info("Initialising " + (name == null ? " Default" : "'" + name + "'") + + " PrincipleDatabase authentication manager."); + + // Fixme This should be done per Vhost but allowing global hack isn't right but ... + // required as authentication is done before Vhost selection + + Map<String, Class<? extends SaslServerFactory>> providerMap = new TreeMap<String, Class<? extends SaslServerFactory>>(); + + + if (name == null) + { + initialiseAuthenticationMechanisms(providerMap, ApplicationRegistry.getInstance().getDatabaseManager().getDatabases()); + } + else + { + String databaseName = hostConfig.getString("security.authentication.name"); + + if (databaseName == null) + { + + if (hostConfig instanceof SubsetConfiguration) + { + _logger.warn("No authentication specified for '" + ((SubsetConfiguration) hostConfig).getPrefix() + "'. Using Default authentication manager"); + } + else + { + _logger.warn("No authentication specified. Using Default authentication manager"); + } + _default = ApplicationRegistry.getInstance().getAuthenticationManager(); + return; + } + else + { + PrincipalDatabase database = ApplicationRegistry.getInstance().getDatabaseManager().getDatabases().get(databaseName); + + if (database == null) + { + throw new ConfigurationException("Requested database:" + databaseName + " was not found"); + } + + initialiseAuthenticationMechanisms(providerMap, database); + } + } + + if (providerMap.size() > 0) + { + Security.addProvider(new JCAProvider(providerMap)); + } + else + { + _logger.warn("No SASL providers availble."); + } + + } + + + private void initialiseAuthenticationMechanisms(Map<String, Class<? extends SaslServerFactory>> providerMap, Map<String, PrincipalDatabase> databases) throws Exception + { +// Configuration config = ApplicationRegistry.getInstance().getConfiguration(); +// List<String> mechanisms = config.getList("security.sasl.mechanisms.mechanism.initialiser.class"); +// +// // Maps from the mechanism to the properties used to initialise the server. See the method +// // Sasl.createSaslServer for details of the use of these properties. This map is populated during initialisation +// // of each provider. + + + if (databases.size() > 1) + { + _logger.warn("More than one principle database provided currently authentication mechanism will override each other."); + } + + for (Map.Entry<String, PrincipalDatabase> entry : databases.entrySet()) + { + + // fixme As the database now provide the mechanisms they support, they will ... + // overwrite each other in the map. There should only be one database per vhost. + // But currently we must have authentication before vhost definition. + initialiseAuthenticationMechanisms(providerMap, entry.getValue()); + } + + } + + private void initialiseAuthenticationMechanisms(Map<String, Class<? extends SaslServerFactory>> providerMap, PrincipalDatabase database) throws Exception + { + if (database == null || database.getMechanisms().size() == 0) + { + _logger.warn(""); + return; + } + + for (AuthenticationProviderInitialiser mechanism : database.getMechanisms().values()) + { + initialiseAuthenticationMechanism(mechanism, providerMap); + } + } + + private void initialiseAuthenticationMechanism(AuthenticationProviderInitialiser initialiser, + Map<String, Class<? extends SaslServerFactory>> providerMap) + throws Exception + { + String mechanism = initialiser.getMechanismName(); + if (_mechanisms == null) + { + _mechanisms = mechanism; + } + else + { + // simple append should be fine since the number of mechanisms is small and this is a one time initialisation + _mechanisms = _mechanisms + " " + mechanism; + } + _callbackHandlerMap.put(mechanism, initialiser.getCallbackHandler()); + _serverCreationProperties.put(mechanism, initialiser.getProperties()); + Class<? extends SaslServerFactory> factory = initialiser.getServerFactoryClassForJCARegistration(); + if (factory != null) + { + providerMap.put(mechanism, factory); + } + _logger.info("Initialised " + mechanism + " SASL provider successfully"); + } + + public String getMechanisms() + { + if (_default != null) + { + // Use the default AuthenticationManager if present + return _default.getMechanisms(); + } + else + { + return _mechanisms; + } + } + + public SaslServer createSaslServer(String mechanism, String localFQDN) throws SaslException + { + if (_default != null) + { + // Use the default AuthenticationManager if present + return _default.createSaslServer(mechanism, localFQDN); + } + else + { + return Sasl.createSaslServer(mechanism, "AMQP", localFQDN, _serverCreationProperties.get(mechanism), + _callbackHandlerMap.get(mechanism)); + } + + } + + public AuthenticationResult authenticate(SaslServer server, byte[] response) + { + // Use the default AuthenticationManager if present + if (_default != null) + { + return _default.authenticate(server, response); + } + + + try + { + // Process response from the client + byte[] challenge = server.evaluateResponse(response != null ? response : new byte[0]); + + if (server.isComplete()) + { + return new AuthenticationResult(challenge, AuthenticationResult.AuthenticationStatus.SUCCESS); + } + else + { + return new AuthenticationResult(challenge, AuthenticationResult.AuthenticationStatus.CONTINUE); + } + } + catch (SaslException e) + { + return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR); + } + } + + public AuthenticationResult isAuthorize(VirtualHost vhost, String username) + { + return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR); + } +} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainInitialiser.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainInitialiser.java deleted file mode 100644 index 9791c13373..0000000000 --- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainInitialiser.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.plain; - -import javax.security.sasl.SaslServerFactory; - -import org.apache.qpid.server.security.auth.UsernamePasswordInitialiser; - -public class PlainInitialiser extends UsernamePasswordInitialiser -{ - public String getMechanismName() - { - return "PLAIN"; - } - - public Class<? extends SaslServerFactory> getServerFactoryClassForJCARegistration() - { - return PlainSaslServerFactory.class; - } -} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainSaslServer.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainSaslServer.java deleted file mode 100644 index 094315dc1f..0000000000 --- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainSaslServer.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.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; - -public class PlainSaslServer implements SaslServer -{ - public static final String MECHANISM = "PLAIN"; - - private CallbackHandler _cbh; - - private String _authorizationId; - - private boolean _complete = false; - - public PlainSaslServer(CallbackHandler cbh) - { - _cbh = cbh; - } - - public String getMechanismName() - { - return MECHANISM; - } - - public byte[] evaluateResponse(byte[] response) throws SaslException - { - try - { - 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"); - } - - // 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 - 1, "utf8"); - - // we do not care about the prompt but it throws if null - NameCallback nameCb = new NameCallback("prompt", authzid); - // we do not care about the prompt but it throws if null - PasswordCallback passwordCb = new PasswordCallback("prompt", false); - // 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"); - passwordCb.setPassword(pwd.toCharArray()); - AuthorizeCallback authzCb = new AuthorizeCallback(authzid, authzid); - Callback[] callbacks = new Callback[]{nameCb, passwordCb, authzCb}; - _cbh.handle(callbacks); - _complete = true; - if (authzCb.isAuthorized()) - { - _authorizationId = authzCb.getAuthenticationID(); - return null; - } - else - { - throw new SaslException("Authentication failed"); - } - } - catch (IOException e) - { - throw new SaslException("Error processing data: " + e, e); - } - catch (UnsupportedCallbackException e) - { - throw new SaslException("Unable to obtain data from callback handler: " + e, e); - } - } - - private int findNullPosition(byte[] response, int startPosition) - { - int position = startPosition; - while (position < response.length) - { - if (response[position] == (byte) 0) - { - return position; - } - position++; - } - return -1; - } - - public boolean isComplete() - { - return _complete; - } - - public String getAuthorizationID() - { - return _authorizationId; - } - - public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException - { - throw new SaslException("Unsupported operation"); - } - - public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException - { - throw new SaslException("Unsupported operation"); - } - - public Object getNegotiatedProperty(String propName) - { - return null; - } - - public void dispose() throws SaslException - { - _cbh = null; - } - -} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainSaslServerFactory.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainSaslServerFactory.java deleted file mode 100644 index 3ea720dd8c..0000000000 --- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/plain/PlainSaslServerFactory.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.auth.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; - -public class PlainSaslServerFactory implements SaslServerFactory -{ - public SaslServer createSaslServer(String mechanism, String protocol, String serverName, Map props, - CallbackHandler cbh) throws SaslException - { - if (PlainSaslServer.MECHANISM.equals(mechanism)) - { - return new PlainSaslServer(cbh); - } - else - { - return null; - } - } - - public String[] getMechanismNames(Map props) - { - if (props.containsKey(Sasl.POLICY_NOPLAINTEXT) || - props.containsKey(Sasl.POLICY_NODICTIONARY) || - props.containsKey(Sasl.POLICY_NOACTIVE)) - { - // returned array must be non null according to interface documentation - return new String[0]; - } - else - { - return new String[]{PlainSaslServer.MECHANISM}; - } - } -} diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationProviderInitialiser.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/AuthenticationProviderInitialiser.java index 19e562517e..89e545d6f5 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationProviderInitialiser.java +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/AuthenticationProviderInitialiser.java @@ -18,7 +18,7 @@ * under the License. * */ -package org.apache.qpid.server.security.auth; +package org.apache.qpid.server.security.auth.sasl; import java.util.Map; @@ -26,6 +26,7 @@ import javax.security.auth.callback.CallbackHandler; import javax.security.sasl.SaslServerFactory; import org.apache.commons.configuration.Configuration; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; public interface AuthenticationProviderInitialiser { @@ -41,11 +42,19 @@ public interface AuthenticationProviderInitialiser * provider can have its own set of configuration options * @param configuration the Apache Commons Configuration instance used to configure this provider * @param principalDatabases the set of principal databases that are available + * @throws Exception needs refined Exception is too broad. */ void initialise(String baseConfigPath, Configuration configuration, Map<String, PrincipalDatabase> principalDatabases) throws Exception; /** + * Initialise the authentication provider. + * @param db The principal database to initialise with + */ + void initialise(PrincipalDatabase db); + + + /** * @return the callback handler that should be used to process authentication requests for this mechanism. This will * be called after initialise and will be stored by the authentication manager. The callback handler <b>must</b> be * fully threadsafe. diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/JCAProvider.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java index ac8eae024e..8ffcdc4e36 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/JCAProvider.java +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java @@ -18,7 +18,7 @@ * under the License. * */ -package org.apache.qpid.server.security.auth; +package org.apache.qpid.server.security.auth.sasl; import java.security.Provider; import java.security.Security; diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/UsernamePasswordInitialiser.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java index d88c6df548..68095de3a0 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/UsernamePasswordInitialiser.java +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java @@ -18,7 +18,7 @@ * under the License. * */ -package org.apache.qpid.server.security.auth; +package org.apache.qpid.server.security.auth.sasl; import java.io.IOException; import java.security.Principal; @@ -33,9 +33,15 @@ 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; public abstract class UsernamePasswordInitialiser implements AuthenticationProviderInitialiser { + protected static final Logger _logger = Logger.getLogger(UsernamePasswordInitialiser.class); + private ServerCallbackHandler _callbackHandler; private class ServerCallbackHandler implements CallbackHandler @@ -54,7 +60,7 @@ public abstract class UsernamePasswordInitialiser implements AuthenticationProvi { if (callback instanceof NameCallback) { - username = new UsernamePrincipal(((NameCallback)callback).getDefaultName()); + username = new UsernamePrincipal(((NameCallback) callback).getDefaultName()); } else if (callback instanceof PasswordCallback) { @@ -71,7 +77,7 @@ public abstract class UsernamePasswordInitialiser implements AuthenticationProvi } else if (callback instanceof AuthorizeCallback) { - ((AuthorizeCallback)callback).setAuthorized(true); + ((AuthorizeCallback) callback).setAuthorized(true); } else { @@ -79,17 +85,22 @@ public abstract class UsernamePasswordInitialiser implements AuthenticationProvi } } } - } + } public void initialise(String baseConfigPath, Configuration configuration, Map<String, PrincipalDatabase> principalDatabases) throws Exception { String principalDatabaseName = configuration.getString(baseConfigPath + ".principal-database"); PrincipalDatabase db = principalDatabases.get(principalDatabaseName); + + initialise(db); + } + + public void initialise(PrincipalDatabase db) + { if (db == null) { - throw new Exception("Principal database " + principalDatabaseName + " not found. Ensure the name matches " + - "an entry in the configuration file"); + throw new NullPointerException("Cannot initialise with a null Principal database."); } _callbackHandler = new ServerCallbackHandler(db); } diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/UsernamePrincipal.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java index e068ba6fe4..f9aaabd15a 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/UsernamePrincipal.java +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java @@ -18,7 +18,7 @@ * under the License. * */ -package org.apache.qpid.server.security.auth; +package org.apache.qpid.server.security.auth.sasl; import java.security.Principal; diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/CRAMMD5Initialiser.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5Initialiser.java index 4e428bbf23..264832888d 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/CRAMMD5Initialiser.java +++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5Initialiser.java @@ -18,12 +18,23 @@ * under the License. * */ -package org.apache.qpid.server.security.auth; +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 javax.security.sasl.SaslServerFactory; public class CRAMMD5Initialiser extends UsernamePasswordInitialiser { + private HashDirection _hashDirection; + + public enum HashDirection + { + INCOMMING, PASSWORD_FILE + } + + public String getMechanismName() { return "CRAM-MD5"; @@ -33,6 +44,28 @@ public class CRAMMD5Initialiser extends UsernamePasswordInitialiser { // since the CRAM-MD5 provider is registered as part of the JDK, we do not // return the factory class here since we do not need to register it ourselves. - return null; + if (_hashDirection == HashDirection.PASSWORD_FILE) + { + return null; + } + else + { + //fixme we need a server that will correctly has the incomming plain text for comparison to file. + _logger.warn("we need a server that will correctly convert the incomming plain text for comparison to file."); + return null; + } + } + + public void initialise(PrincipalDatabase passwordFile) + { + initialise(passwordFile, HashDirection.PASSWORD_FILE); } + + public void initialise(PrincipalDatabase passwordFile, HashDirection direction) + { + super.initialise(passwordFile); + + _hashDirection = direction; + } + } diff --git a/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java index 217a524562..150b98b424 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java +++ b/java/broker/src/main/java/org/apache/qpid/server/util/NullApplicationRegistry.java @@ -23,14 +23,19 @@ package org.apache.qpid.server.util; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; +import java.util.Properties; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.MapConfiguration; import org.apache.qpid.server.management.ManagedObjectRegistry; import org.apache.qpid.server.management.NoopManagedObjectRegistry; import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.security.auth.AuthenticationManager; -import org.apache.qpid.server.security.auth.NullAuthenticationManager; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; +import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; +import org.apache.qpid.server.security.auth.database.PropertiesPrincipalDatabaseManager; +import org.apache.qpid.server.security.access.AccessManager; +import org.apache.qpid.server.security.access.AllowAll; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; @@ -42,6 +47,10 @@ public class NullApplicationRegistry extends ApplicationRegistry private VirtualHostRegistry _virtualHostRegistry; + private AccessManager _accessManager; + + private PrincipalDatabaseManager _databaseManager; + public NullApplicationRegistry() { @@ -50,14 +59,23 @@ public class NullApplicationRegistry extends ApplicationRegistry public void initialise() throws Exception { - _configuration.addProperty("store.class","org.apache.qpid.server.store.MemoryMessageStore"); + _configuration.addProperty("store.class", "org.apache.qpid.server.store.MemoryMessageStore"); + + Properties users = new Properties(); + + users.put("guest", "guest"); + + _databaseManager = new PropertiesPrincipalDatabaseManager("default", users); + + _accessManager = new AllowAll(); + + _authenticationManager = new PrincipalDatabaseAuthenticationManager(null, null); _managedObjectRegistry = new NoopManagedObjectRegistry(); _virtualHostRegistry = new VirtualHostRegistry(); - VirtualHost dummyHost = new VirtualHost("test",getConfiguration()); + VirtualHost dummyHost = new VirtualHost("test", getConfiguration()); _virtualHostRegistry.registerVirtualHost(dummyHost); _virtualHostRegistry.setDefaultVirtualHostName("test"); - _authenticationManager = new NullAuthenticationManager(); _configuration.addProperty("heartbeat.delay", 10 * 60); // 10 minutes @@ -74,6 +92,11 @@ public class NullApplicationRegistry extends ApplicationRegistry return _managedObjectRegistry; } + public PrincipalDatabaseManager getDatabaseManager() + { + return _databaseManager; + } + public AuthenticationManager getAuthenticationManager() { return _authenticationManager; @@ -81,14 +104,19 @@ public class NullApplicationRegistry extends ApplicationRegistry public Collection<String> getVirtualHostNames() { - String[] hosts = {"test"}; - return Arrays.asList( hosts ); + String[] hosts = {"test"}; + return Arrays.asList(hosts); } public VirtualHostRegistry getVirtualHostRegistry() { return _virtualHostRegistry; } + + public AccessManager getAccessManager() + { + return _accessManager; + } } diff --git a/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index e09ce9326c..c24d1aa23a 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -25,6 +25,11 @@ import javax.management.NotCompliantMBeanException; import org.apache.commons.configuration.Configuration;
import org.apache.log4j.Logger;
import org.apache.qpid.server.AMQBrokerManagerMBean;
+import org.apache.qpid.server.security.access.AccessManager;
+import org.apache.qpid.server.security.access.AccessManagerImpl;
+import org.apache.qpid.server.security.access.Accessable;
+import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager;
+import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
import org.apache.qpid.server.configuration.Configurator;
import org.apache.qpid.server.exchange.DefaultExchangeFactory;
import org.apache.qpid.server.exchange.DefaultExchangeRegistry;
@@ -37,7 +42,7 @@ import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.store.MessageStore;
-public class VirtualHost
+public class VirtualHost implements Accessable
{
private static final Logger _logger = Logger.getLogger(VirtualHost.class);
@@ -50,84 +55,103 @@ public class VirtualHost private ExchangeFactory _exchangeFactory;
- private MessageStore _messageStore;
+ private MessageStore _messageStore;
protected VirtualHostMBean _virtualHostMBean;
private AMQBrokerManagerMBean _brokerMBean;
+ private AuthenticationManager _authenticationManager;
- /**
- * Abstract MBean class. This has some of the methods implemented from
- * management intrerface for exchanges. Any implementaion of an
- * Exchange MBean should extend this class.
- */
- public class VirtualHostMBean extends AMQManagedObject implements ManagedVirtualHost
- {
- public VirtualHostMBean() throws NotCompliantMBeanException
- {
- super(ManagedVirtualHost.class, "VirtualHost");
- }
+ private AccessManager _accessManager;
- public String getObjectInstanceName()
- {
- return _name.toString();
- }
+ public void setAccessableName(String name)
+ {
+ _logger.warn("Setting Accessable Name for VirualHost is not allowed. ("
+ + name + ") ignored remains :" + getAccessableName());
+ }
- public String getName()
- {
- return _name.toString();
- }
+ public String getAccessableName()
+ {
+ return _name;
+ }
- public VirtualHost getVirtualHost()
- {
- return VirtualHost.this;
- }
+ /**
+ * Abstract MBean class. This has some of the methods implemented from management intrerface for exchanges. Any
+ * implementaion of an Exchange MBean should extend this class.
+ */
+ public class VirtualHostMBean extends AMQManagedObject implements ManagedVirtualHost
+ {
+ public VirtualHostMBean() throws NotCompliantMBeanException
+ {
+ super(ManagedVirtualHost.class, "VirtualHost");
+ }
- } // End of MBean class
+ public String getObjectInstanceName()
+ {
+ return _name.toString();
+ }
+ public String getName()
+ {
+ return _name.toString();
+ }
- public VirtualHost(String name, MessageStore store) throws Exception
- {
- _name = name;
+ public VirtualHost getVirtualHost()
+ {
+ return VirtualHost.this;
+ }
- _virtualHostMBean = new VirtualHostMBean();
- // This isn't needed to be registered
- //_virtualHostMBean.register();
- _queueRegistry = new DefaultQueueRegistry(this);
- _exchangeFactory = new DefaultExchangeFactory(this);
- _exchangeRegistry = new DefaultExchangeRegistry(this);
-
- _messageStore = store;
-
- _exchangeRegistry.initialise();
+ } // End of MBean class
- _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean);
- _brokerMBean.register();
+ public VirtualHost(String name, MessageStore store) throws Exception
+ {
+ this(name, null, store);
}
+
public VirtualHost(String name, Configuration hostConfig) throws Exception
{
+ this(name, hostConfig, null);
+ }
+
+ private VirtualHost(String name, Configuration hostConfig, MessageStore store) throws Exception
+ {
_name = name;
_virtualHostMBean = new VirtualHostMBean();
// This isn't needed to be registered
//_virtualHostMBean.register();
-
+
_queueRegistry = new DefaultQueueRegistry(this);
_exchangeFactory = new DefaultExchangeFactory(this);
_exchangeRegistry = new DefaultExchangeRegistry(this);
- initialiseMessageStore(hostConfig);
+ if (store != null)
+ {
+ _messageStore = store;
+ }
+ else
+ {
+ if (hostConfig == null)
+ {
+ throw new IllegalAccessException("HostConfig and MessageStore cannot be null");
+ }
+ initialiseMessageStore(hostConfig);
+ }
_exchangeRegistry.initialise();
+ _logger.warn("VirtualHost authentication Managers require spec change to be operational.");
+ _authenticationManager = new PrincipalDatabaseAuthenticationManager(name, hostConfig);
+
+ _accessManager = new AccessManagerImpl(name, hostConfig);
+
_brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean);
_brokerMBean.register();
-
}
private void initialiseMessageStore(Configuration config) throws Exception
@@ -140,15 +164,13 @@ public class VirtualHost if (!(o instanceof MessageStore))
{
throw new ClassCastException("Message store class must implement " + MessageStore.class + ". Class " + clazz +
- " does not.");
+ " does not.");
}
_messageStore = (MessageStore) o;
_messageStore.configure(this, "store", config);
}
-
-
public <T> T getConfiguredObject(Class<T> instanceType, Configuration config)
{
T instance;
@@ -171,7 +193,7 @@ public class VirtualHost {
return _name;
}
-
+
public QueueRegistry getQueueRegistry()
{
return _queueRegistry;
@@ -189,7 +211,7 @@ public class VirtualHost public ApplicationRegistry getApplicationRegistry()
{
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException();
}
public MessageStore getMessageStore()
@@ -197,9 +219,19 @@ public class VirtualHost return _messageStore;
}
+ public AuthenticationManager getAuthenticationManager()
+ {
+ return _authenticationManager;
+ }
+
+ public AccessManager getAccessManager()
+ {
+ return _accessManager;
+ }
+
public void close() throws Exception
{
- if(_messageStore != null)
+ if (_messageStore != null)
{
_messageStore.close();
}
@@ -210,8 +242,6 @@ public class VirtualHost return _brokerMBean;
}
-
-
public ManagedObject getManagedObject()
{
return _virtualHostMBean;
diff --git a/java/client/src/old_test/java/org/apache/qpid/flow/ChannelFlowTest.java b/java/client/src/old_test/java/org/apache/qpid/flow/ChannelFlowTest.java index aba2d5d657..cb8adae18c 100644 --- a/java/client/src/old_test/java/org/apache/qpid/flow/ChannelFlowTest.java +++ b/java/client/src/old_test/java/org/apache/qpid/flow/ChannelFlowTest.java @@ -38,7 +38,7 @@ public class ChannelFlowTest implements MessageListener ChannelFlowTest(String broker) throws Exception { - this(new AMQConnection(broker, "guest", "guest", randomize("Client"), "/test_path")); + this(new AMQConnection(broker, "guest", "guest", randomize("Client"), "/test")); } ChannelFlowTest(AMQConnection connection) throws Exception diff --git a/java/client/src/old_test/java/org/apache/qpid/latency/LatencyTest.java b/java/client/src/old_test/java/org/apache/qpid/latency/LatencyTest.java index 8d833f4d4c..4865a68dc4 100644 --- a/java/client/src/old_test/java/org/apache/qpid/latency/LatencyTest.java +++ b/java/client/src/old_test/java/org/apache/qpid/latency/LatencyTest.java @@ -48,7 +48,7 @@ public class LatencyTest implements MessageListener LatencyTest(String broker, int count, int delay, int length) throws Exception { - this(new AMQConnection(broker, "guest", "guest", randomize("Client"), "/test_path"), count, delay, length); + this(new AMQConnection(broker, "guest", "guest", randomize("Client"), "/test"), count, delay, length); } LatencyTest(AMQConnection connection, int count, int delay, int length) throws Exception diff --git a/java/client/src/test/java/org/apache/qpid/client/DispatcherTest.java b/java/client/src/test/java/org/apache/qpid/client/DispatcherTest.java index cf26a54f1b..1d85ea47fd 100644 --- a/java/client/src/test/java/org/apache/qpid/client/DispatcherTest.java +++ b/java/client/src/test/java/org/apache/qpid/client/DispatcherTest.java @@ -82,7 +82,7 @@ public class DispatcherTest extends TestCase Hashtable<String, String> env = new Hashtable<String, String>(); - env.put("connectionfactory.connection", "amqp://client:client@MLT_ID/test?brokerlist='vm://:1'"); + env.put("connectionfactory.connection", "amqp://guest:guest@MLT_ID/test?brokerlist='vm://:1'"); env.put("queue.queue", "MessageListenerTest"); _context = factory.getInitialContext(env); diff --git a/java/client/src/test/java/org/apache/qpid/client/MessageListenerMultiConsumerTest.java b/java/client/src/test/java/org/apache/qpid/client/MessageListenerMultiConsumerTest.java index 6062528d43..a406f9f86e 100644 --- a/java/client/src/test/java/org/apache/qpid/client/MessageListenerMultiConsumerTest.java +++ b/java/client/src/test/java/org/apache/qpid/client/MessageListenerMultiConsumerTest.java @@ -74,7 +74,7 @@ public class MessageListenerMultiConsumerTest extends TestCase Hashtable<String, String> env = new Hashtable<String, String>(); - env.put("connectionfactory.connection", "amqp://client:client@MLT_ID/test?brokerlist='vm://:1'"); + env.put("connectionfactory.connection", "amqp://guest:guest@MLT_ID/test?brokerlist='vm://:1'"); env.put("queue.queue", "direct://amq.direct//MessageListenerTest"); _context = factory.getInitialContext(env); diff --git a/java/client/src/test/java/org/apache/qpid/client/MessageListenerTest.java b/java/client/src/test/java/org/apache/qpid/client/MessageListenerTest.java index dc01005247..5fb77af4db 100644 --- a/java/client/src/test/java/org/apache/qpid/client/MessageListenerTest.java +++ b/java/client/src/test/java/org/apache/qpid/client/MessageListenerTest.java @@ -73,7 +73,7 @@ public class MessageListenerTest extends TestCase implements MessageListener Hashtable<String, String> env = new Hashtable<String, String>(); - env.put("connectionfactory.connection", "amqp://client:client@MLT_ID/test?brokerlist='vm://:1'"); + env.put("connectionfactory.connection", "amqp://guest:guest@MLT_ID/test?brokerlist='vm://:1'"); env.put("queue.queue", "MessageListenerTest"); _context = factory.getInitialContext(env); diff --git a/java/client/src/test/java/org/apache/qpid/client/ResetMessageListenerTest.java b/java/client/src/test/java/org/apache/qpid/client/ResetMessageListenerTest.java index 08501c9554..10bf1a8d6d 100644 --- a/java/client/src/test/java/org/apache/qpid/client/ResetMessageListenerTest.java +++ b/java/client/src/test/java/org/apache/qpid/client/ResetMessageListenerTest.java @@ -82,7 +82,7 @@ public class ResetMessageListenerTest extends TestCase Hashtable<String, String> env = new Hashtable<String, String>(); - env.put("connectionfactory.connection", "amqp://client:client@MLT_ID/test?brokerlist='vm://:1'"); + env.put("connectionfactory.connection", "amqp://guest:guest@MLT_ID/test?brokerlist='vm://:1'"); env.put("queue.queue", "direct://amq.direct//MessageListenerTest"); _context = factory.getInitialContext(env); diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionTest.java index d9ce080e14..ab0d26b0e0 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionTest.java @@ -73,7 +73,7 @@ public class ConnectionTest extends TestCase { try { - AMQConnection conn = new AMQConnection("amqp://guest:guestd@clientid/test?brokerlist='" + AMQConnection conn = new AMQConnection("amqp://guest:guest@clientid/test?brokerlist='" + _broker + "?retries='1''&defaultQueueExchange='test.direct'" + "&defaultTopicExchange='test.topic'" @@ -115,13 +115,12 @@ public class ConnectionTest extends TestCase } } - - // FIXME The inVM broker currently has no authentication .. Needs added QPID-70 - public void passwordFailureConnection() throws Exception + //fixme AMQAuthenticationException is not propogaged + public void PasswordFailureConnection() throws Exception { try { - new AMQConnection("amqp://guest:rubbishpassword@clientid/testpath?brokerlist='" + _broker + "?retries='1''"); + new AMQConnection("amqp://guest:rubbishpassword@clientid/test?brokerlist='" + _broker + "?retries='1''"); fail("Connection should not be established password is wrong."); } catch (AMQException amqe) diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/close/CloseBeforeAckTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/close/CloseBeforeAckTest.java index 5cee306846..117696196e 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/close/CloseBeforeAckTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/close/CloseBeforeAckTest.java @@ -41,10 +41,8 @@ import uk.co.thebadgerset.junit.concurrency.ThreadTestCoordinator; * Running in AUTO_ACK mode, the close call ought to wait until the onMessage method completes, and the ack is sent
* before closing the connection.
*
- * <p><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Check that closing a connection whilst handling a message, blocks till completion of the handler.
- * </table>
+ * <p><table id="crc"><caption>CRC Card</caption> <tr><th> Responsibilities <th> Collaborations <tr><td> Check that
+ * closing a connection whilst handling a message, blocks till completion of the handler. </table>
*/
public class CloseBeforeAckTest extends TestCase
{
@@ -53,6 +51,7 @@ public class CloseBeforeAckTest extends TestCase Connection connection;
Session session;
public static final String TEST_QUEUE_NAME = "TestQueue";
+ private int TEST_COUNT = 25;
class TestThread1 extends TestRunnable implements MessageListener
{
@@ -65,34 +64,34 @@ public class CloseBeforeAckTest extends TestCase public void onMessage(Message message)
{
// Give thread 2 permission to close the session.
- allow(new int[] { 1 });
+ allow(new int[]{1});
// Wait until thread 2 has closed the connection, or is blocked waiting for this to complete.
- waitFor(new int[] { 1 }, true);
+ waitFor(new int[]{1}, true);
}
}
TestThread1 testThread1 = new TestThread1();
TestRunnable testThread2 =
- new TestRunnable()
- {
- public void runWithExceptions() throws Exception
+ new TestRunnable()
{
- // Send a message to be picked up by thread 1.
- session.createProducer(null).send(session.createQueue(TEST_QUEUE_NAME),
- session.createTextMessage("Hi there thread 1!"));
+ public void runWithExceptions() throws Exception
+ {
+ // Send a message to be picked up by thread 1.
+ session.createProducer(null).send(session.createQueue(TEST_QUEUE_NAME),
+ session.createTextMessage("Hi there thread 1!"));
- // Wait for thread 1 to pick up the message and give permission to continue.
- waitFor(new int[] { 0 }, false);
+ // Wait for thread 1 to pick up the message and give permission to continue.
+ waitFor(new int[]{0}, false);
- // Close the connection.
- session.close();
+ // Close the connection.
+ session.close();
- // Allow thread 1 to continue to completion, if it is erronously still waiting.
- allow(new int[] { 1 });
- }
- };
+ // Allow thread 1 to continue to completion, if it is erronously still waiting.
+ allow(new int[]{1});
+ }
+ };
public void testCloseBeforeAutoAck_QPID_397() throws Exception
{
@@ -123,9 +122,9 @@ public class CloseBeforeAckTest extends TestCase Assert.assertTrue(errorMessage, "".equals(errorMessage));
}
- public void testCloseBeforeAutoAckManyTimes() throws Exception
+ public void closeBeforeAutoAckManyTimes() throws Exception
{
- for (int i = 0; i < 500; i++)
+ for (int i = 0; i < TEST_COUNT; i++)
{
testCloseBeforeAutoAck_QPID_397();
}
diff --git a/java/client/src/test/java/org/apache/qpid/testutil/Config.java b/java/client/src/test/java/org/apache/qpid/testutil/Config.java index e5b4834622..8109d20a33 100644 --- a/java/client/src/test/java/org/apache/qpid/testutil/Config.java +++ b/java/client/src/test/java/org/apache/qpid/testutil/Config.java @@ -136,7 +136,7 @@ public class Config public Connection getConnection() throws Exception { System.out.println("Connecting to " + host + " on " + port + "..."); - return new AMQConnection(host, port, "guest", "guest", "Client" + System.currentTimeMillis(), "/test_path"); + return new AMQConnection(host, port, "guest", "guest", "Client" + System.currentTimeMillis(), "/test"); } public boolean setOptions(String[] argv) diff --git a/java/systests/src/main/java/org/apache/qpid/server/queue/MockProtocolSession.java b/java/systests/src/main/java/org/apache/qpid/server/queue/MockProtocolSession.java index 508d88f941..8795adbc55 100644 --- a/java/systests/src/main/java/org/apache/qpid/server/queue/MockProtocolSession.java +++ b/java/systests/src/main/java/org/apache/qpid/server/queue/MockProtocolSession.java @@ -177,6 +177,16 @@ public class MockProtocolSession implements AMQProtocolSession return ProtocolOutputConverterRegistry.getConverter(this); } + public void setAuthorizedID(String authorizedID) + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public String getAuthorizedID() + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + public byte getProtocolMajorVersion() { return 8; //To change body of implemented methods use File | Settings | File Templates. diff --git a/java/systests/src/main/java/org/apache/qpid/server/util/TestApplicationRegistry.java b/java/systests/src/main/java/org/apache/qpid/server/util/TestApplicationRegistry.java index 849285e6d6..bd7ed60d1d 100644 --- a/java/systests/src/main/java/org/apache/qpid/server/util/TestApplicationRegistry.java +++ b/java/systests/src/main/java/org/apache/qpid/server/util/TestApplicationRegistry.java @@ -20,18 +20,18 @@ */ package org.apache.qpid.server.util; -import org.apache.qpid.server.exchange.DefaultExchangeFactory; -import org.apache.qpid.server.exchange.DefaultExchangeRegistry; import org.apache.qpid.server.exchange.ExchangeFactory; import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.server.management.ManagedObjectRegistry; -import org.apache.qpid.server.management.NoopManagedObjectRegistry; -import org.apache.qpid.server.queue.DefaultQueueRegistry; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.registry.IApplicationRegistry; -import org.apache.qpid.server.security.auth.AuthenticationManager; -import org.apache.qpid.server.security.auth.NullAuthenticationManager; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; +import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; +import org.apache.qpid.server.security.auth.database.PropertiesPrincipalDatabaseManager; +import org.apache.qpid.server.security.access.AccessManager; +import org.apache.qpid.server.security.access.AllowAll; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.TestableMemoryMessageStore; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -41,6 +41,7 @@ import org.apache.commons.configuration.MapConfiguration; import java.util.HashMap; import java.util.Collection; +import java.util.Properties; public class TestApplicationRegistry extends ApplicationRegistry { @@ -52,6 +53,10 @@ public class TestApplicationRegistry extends ApplicationRegistry private ManagedObjectRegistry _managedObjectRegistry; + private AccessManager _accessManager; + + private PrincipalDatabaseManager _databaseManager; + private AuthenticationManager _authenticationManager; private MessageStore _messageStore; @@ -64,13 +69,23 @@ public class TestApplicationRegistry extends ApplicationRegistry public void initialise() throws Exception { + Properties users = new Properties(); + + users.put("guest", "guest"); + + _databaseManager = new PropertiesPrincipalDatabaseManager("default", users); + + _accessManager = new AllowAll(); + + _authenticationManager = new PrincipalDatabaseAuthenticationManager(null, null); + IApplicationRegistry appRegistry = ApplicationRegistry.getInstance(); _managedObjectRegistry = appRegistry.getManagedObjectRegistry(); _vHost = appRegistry.getVirtualHostRegistry().getVirtualHost("test"); _queueRegistry = _vHost.getQueueRegistry(); _exchangeFactory = _vHost.getExchangeFactory(); _exchangeRegistry = _vHost.getExchangeRegistry(); - _authenticationManager = new NullAuthenticationManager(); + _messageStore = new TestableMemoryMessageStore(); _configuration.addProperty("heartbeat.delay", 10 * 60); // 10 minutes @@ -101,6 +116,11 @@ public class TestApplicationRegistry extends ApplicationRegistry return _managedObjectRegistry; } + public PrincipalDatabaseManager getDatabaseManager() + { + return _databaseManager; + } + public AuthenticationManager getAuthenticationManager() { return _authenticationManager; @@ -116,6 +136,11 @@ public class TestApplicationRegistry extends ApplicationRegistry return null; //To change body of implemented methods use File | Settings | File Templates. } + public AccessManager getAccessManager() + { + return _accessManager; + } + public MessageStore getMessageStore() { return _messageStore; diff --git a/java/systests/src/main/java/org/apache/qpid/test/VMTestCase.java b/java/systests/src/main/java/org/apache/qpid/test/VMTestCase.java index bbac06382d..31fd77691d 100644 --- a/java/systests/src/main/java/org/apache/qpid/test/VMTestCase.java +++ b/java/systests/src/main/java/org/apache/qpid/test/VMTestCase.java @@ -84,7 +84,7 @@ public class VMTestCase extends TestCase _brokerlist = "vm://:1"; } - env.put("connectionfactory.connection", "amqp://client:client@" + + env.put("connectionfactory.connection", "amqp://guest:guest@" + _clientID + _virtualhost + "?brokerlist='" + _brokerlist + "'"); for (Map.Entry<String, String> c : _connections.entrySet()) |
