diff options
| author | Martin Ritchie <ritchiem@apache.org> | 2007-03-16 14:46:42 +0000 |
|---|---|---|
| committer | Martin Ritchie <ritchiem@apache.org> | 2007-03-16 14:46:42 +0000 |
| commit | e646a1a4bc7c9bbfaa005390791b7f11105f55ec (patch) | |
| tree | c11af3563313c20f0e3c4d4978359bbdde3309bb /java | |
| parent | c8151b51d14a2c2f60aa86cd70ee5b37ac0bd501 (diff) | |
| download | qpid-python-e646a1a4bc7c9bbfaa005390791b7f11105f55ec.tar.gz | |
QPID-70 InVM Authentication QPID-419 Access Control QPID-423 Authentication per virtualhost
Restructured auth package.
Enabled InVM Authentication
Initial changes to allow authenticators per virtualhost.
Initial access control classes.
Initial work to allow access control testing through inVM broker.
git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid@518988 13f79535-47bb-0310-9956-ffa450edef68
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()) |
