| /* |
| * 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.acl; |
| |
| import java.io.IOException; |
| |
| import javax.jms.Connection; |
| import javax.jms.DeliveryMode; |
| import javax.jms.IllegalStateException; |
| import javax.jms.JMSException; |
| import javax.jms.Message; |
| import javax.jms.MessageConsumer; |
| import javax.jms.MessageProducer; |
| import javax.jms.Queue; |
| import javax.jms.Session; |
| import javax.jms.TextMessage; |
| import javax.jms.Topic; |
| import javax.jms.TopicSubscriber; |
| import javax.naming.NamingException; |
| |
| import org.apache.qpid.AMQException; |
| import org.apache.qpid.client.AMQConnection; |
| import org.apache.qpid.client.AMQSession; |
| import org.apache.qpid.framing.AMQShortString; |
| import org.apache.qpid.protocol.AMQConstant; |
| import org.apache.qpid.url.URLSyntaxException; |
| |
| /** |
| * Basic access control list tests. |
| * |
| * These tests require an access control security plugin to be configured in the broker, and carry out various broker |
| * operations that will succeed or fail depending on the user and virtual host. See the {@code config-systests-acl-setup.xml} |
| * configuration file for the SimpleXML version of the ACLs used by the Java broker only, or the various {@code .txt} |
| * files in the system tests directory for the external version 3 ACL files used by both the Java and C++ brokers. |
| * <p> |
| * This class can be extended and the {@link #getConfig()} method overridden to run the same tests with a different type |
| * of access control mechanism. Extension classes should differ only in the configuration file used, but extra tests can be |
| * added that are specific to a particular configuration. |
| * <p> |
| * The tests perform basic AMQP operations like creating queues or excahnges and publishing and consuming messages, using |
| * JMS to contact the broker. |
| * |
| * @see ExternalACLTest |
| */ |
| public class SimpleACLTest extends AbstractACLTestCase |
| { |
| public void testAccessAuthorizedSuccess() throws AMQException, URLSyntaxException, Exception |
| { |
| try |
| { |
| Connection conn = getConnection("test", "client", "guest"); |
| Session sess = conn.createSession(true, Session.SESSION_TRANSACTED); |
| conn.start(); |
| |
| //Do something to show connection is active. |
| sess.rollback(); |
| |
| conn.close(); |
| } |
| catch (Exception e) |
| { |
| fail("Connection was not created due to:" + e); |
| } |
| } |
| |
| public void testAccessVhostAuthorisedGuestSuccess() throws IOException, Exception |
| { |
| //The 'guest' user has no access to the 'test' vhost, as tested below in testAccessNoRights(), and so |
| //is unable to perform actions such as connecting (and by extension, creating a queue, and consuming |
| //from a queue etc). In order to test the vhost-wide 'access' ACL right, the 'guest' user has been given |
| //this right in the 'test2' vhost. |
| |
| try |
| { |
| //get a connection to the 'test2' vhost using the guest user and perform various actions. |
| Connection conn = getConnection("test2", "guest", "guest"); |
| Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); |
| conn.start(); |
| |
| //create Queues and consumers for each |
| Queue namedQueue = sess.createQueue("vhostAccessCreatedQueue" + getTestQueueName()); |
| Queue tempQueue = sess.createTemporaryQueue(); |
| MessageConsumer consumer = sess.createConsumer(namedQueue); |
| MessageConsumer tempConsumer = sess.createConsumer(tempQueue); |
| |
| //send a message to each queue (also causing an exchange declare) |
| MessageProducer sender = ((AMQSession<?, ?>) sess).createProducer(null); |
| ((org.apache.qpid.jms.MessageProducer) sender).send(namedQueue, sess.createTextMessage("test"), |
| DeliveryMode.NON_PERSISTENT, 0, 0L, false, false, true); |
| ((org.apache.qpid.jms.MessageProducer) sender).send(tempQueue, sess.createTextMessage("test"), |
| DeliveryMode.NON_PERSISTENT, 0, 0L, false, false, true); |
| |
| //consume the messages from the queues |
| consumer.receive(2000); |
| tempConsumer.receive(2000); |
| |
| conn.close(); |
| } |
| catch (Exception e) |
| { |
| fail("Test failed due to:" + e.getMessage()); |
| } |
| } |
| |
| public void testAccessNoRightsFailure() throws Exception |
| { |
| try |
| { |
| Connection conn = getConnection("test", "guest", "guest"); |
| Session sess = conn.createSession(true, Session.SESSION_TRANSACTED); |
| conn.start(); |
| sess.rollback(); |
| |
| fail("Connection was created."); |
| } |
| catch (JMSException e) |
| { |
| // JMSException -> linkedException -> cause = AMQException (403 or 320) |
| Exception linkedException = e.getLinkedException(); |
| assertNotNull("There was no linked exception", linkedException); |
| Throwable cause = linkedException.getCause(); |
| assertNotNull("Cause was null", cause); |
| assertTrue("Wrong linked exception type", cause instanceof AMQException); |
| AMQConstant errorCode = isBroker010() ? AMQConstant.CONTEXT_IN_USE : AMQConstant.ACCESS_REFUSED; |
| assertEquals("Incorrect error code received", errorCode, ((AMQException) cause).getErrorCode()); |
| } |
| } |
| |
| public void testClientDeleteQueueSuccess() throws Exception |
| { |
| try |
| { |
| Connection conn = getConnection("test", "client", "guest"); |
| Session sess = conn.createSession(true, Session.SESSION_TRANSACTED); |
| conn.start(); |
| |
| // create kipper |
| Topic kipper = sess.createTopic("kipper"); |
| TopicSubscriber subscriber = sess.createDurableSubscriber(kipper, "kipper"); |
| |
| subscriber.close(); |
| sess.unsubscribe("kipper"); |
| |
| //Do something to show connection is active. |
| sess.rollback(); |
| conn.close(); |
| } |
| catch (Exception e) |
| { |
| fail("Test failed due to:" + e.getMessage()); |
| } |
| } |
| |
| public void testServerDeleteQueueFailure() throws Exception |
| { |
| try |
| { |
| Connection conn = getConnection("test", "server", "guest"); |
| Session sess = conn.createSession(true, Session.SESSION_TRANSACTED); |
| conn.start(); |
| |
| // create kipper |
| Topic kipper = sess.createTopic("kipper"); |
| TopicSubscriber subscriber = sess.createDurableSubscriber(kipper, "kipper"); |
| |
| subscriber.close(); |
| sess.unsubscribe("kipper"); |
| |
| //Do something to show connection is active. |
| sess.rollback(); |
| conn.close(); |
| } |
| catch (JMSException e) |
| { |
| // JMSException -> linedException = AMQException.403 |
| check403Exception(e.getLinkedException()); |
| } |
| } |
| |
| public void testClientConsumeFromTempQueueSuccess() throws AMQException, URLSyntaxException, Exception |
| { |
| try |
| { |
| Connection conn = getConnection("test", "client", "guest"); |
| |
| Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); |
| |
| conn.start(); |
| |
| sess.createConsumer(sess.createTemporaryQueue()); |
| |
| conn.close(); |
| } |
| catch (Exception e) |
| { |
| fail("Test failed due to:" + e.getMessage()); |
| } |
| } |
| |
| public void testClientConsumeFromNamedQueueFailure() throws NamingException, Exception |
| { |
| try |
| { |
| Connection conn = getConnection("test", "client", "guest"); |
| |
| Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); |
| |
| conn.start(); |
| |
| sess.createConsumer(sess.createQueue("IllegalQueue")); |
| |
| fail("Test failed as consumer was created."); |
| } |
| catch (JMSException e) |
| { |
| check403Exception(e.getLinkedException()); |
| } |
| } |
| |
| public void testClientCreateTemporaryQueueSuccess() throws JMSException, URLSyntaxException, Exception |
| { |
| try |
| { |
| Connection conn = getConnection("test", "client", "guest"); |
| |
| Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); |
| |
| conn.start(); |
| |
| //Create Temporary Queue - can't use the createTempQueue as QueueName is null. |
| ((AMQSession<?, ?>) sess).createQueue(new AMQShortString("doesnt_matter_as_autodelete_means_tmp"), |
| true, false, false); |
| |
| conn.close(); |
| } |
| catch (Exception e) |
| { |
| fail("Test failed due to:" + e.getMessage()); |
| } |
| } |
| |
| public void testClientCreateNamedQueueFailure() throws NamingException, JMSException, AMQException, Exception |
| { |
| try |
| { |
| Connection conn = getConnection("test", "client", "guest"); |
| |
| Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); |
| |
| conn.start(); |
| |
| //Create a Named Queue |
| ((AMQSession<?, ?>) sess).createQueue(new AMQShortString("IllegalQueue"), false, false, false); |
| |
| fail("Test failed as Queue creation succeded."); |
| //conn will be automatically closed |
| } |
| catch (AMQException e) |
| { |
| check403Exception(e); |
| } |
| } |
| |
| public void testClientPublishUsingTransactionSuccess() throws AMQException, URLSyntaxException, Exception |
| { |
| try |
| { |
| Connection conn = getConnection("test", "client", "guest"); |
| |
| Session sess = conn.createSession(true, Session.SESSION_TRANSACTED); |
| |
| conn.start(); |
| |
| MessageProducer sender = sess.createProducer(sess.createQueue("example.RequestQueue")); |
| |
| sender.send(sess.createTextMessage("test")); |
| |
| //Send the message using a transaction as this will allow us to retrieve any errors that occur on the broker. |
| sess.commit(); |
| |
| conn.close(); |
| } |
| catch (Exception e) |
| { |
| fail("Test publish failed:" + e); |
| } |
| } |
| |
| public void testClientPublishValidQueueSuccess() throws AMQException, URLSyntaxException, Exception |
| { |
| try |
| { |
| Connection conn = getConnection("test", "client", "guest"); |
| |
| Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); |
| |
| conn.start(); |
| |
| MessageProducer sender = ((AMQSession<?, ?>) sess).createProducer(null); |
| |
| Queue queue = sess.createQueue("example.RequestQueue"); |
| |
| // Send a message that we will wait to be sent, this should give the broker time to process the msg |
| // before we finish this test. Message is set !immed !mand as the queue is invalid so want to test ACLs not |
| // queue existence. |
| ((org.apache.qpid.jms.MessageProducer) sender).send(queue, sess.createTextMessage("test"), |
| DeliveryMode.NON_PERSISTENT, 0, 0L, false, false, true); |
| |
| conn.close(); |
| } |
| catch (Exception e) |
| { |
| fail("Test publish failed:" + e); |
| } |
| } |
| |
| public void testClientPublishInvalidQueueSuccess() throws AMQException, URLSyntaxException, JMSException, NamingException, Exception |
| { |
| try |
| { |
| Connection conn = getConnection("test", "client", "guest"); |
| |
| Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); |
| |
| conn.start(); |
| |
| MessageProducer sender = ((AMQSession<?, ?>) session).createProducer(null); |
| |
| Queue queue = session.createQueue("Invalid"); |
| |
| // Send a message that we will wait to be sent, this should give the broker time to close the connection |
| // before we finish this test. Message is set !immed !mand as the queue is invalid so want to test ACLs not |
| // queue existence. |
| ((org.apache.qpid.jms.MessageProducer) sender).send(queue, session.createTextMessage("test"), |
| DeliveryMode.NON_PERSISTENT, 0, 0L, false, false, true); |
| |
| // Test the connection with a valid consumer |
| // This may fail as the session may be closed before the queue or the consumer created. |
| Queue temp = session.createTemporaryQueue(); |
| |
| session.createConsumer(temp).close(); |
| |
| //Connection should now be closed and will throw the exception caused by the above send |
| conn.close(); |
| |
| fail("Close is not expected to succeed."); |
| } |
| catch (IllegalStateException e) |
| { |
| _logger.info("QPID-2345: Session became closed and we got that error rather than the authentication error."); |
| } |
| catch (JMSException e) |
| { |
| check403Exception(e.getLinkedException()); |
| } |
| } |
| |
| public void testServerConsumeFromNamedQueueValid() throws AMQException, URLSyntaxException, Exception |
| { |
| try |
| { |
| Connection conn = getConnection("test", "server", "guest"); |
| |
| Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); |
| |
| conn.start(); |
| |
| sess.createConsumer(sess.createQueue("example.RequestQueue")); |
| |
| conn.close(); |
| } |
| catch (Exception e) |
| { |
| fail("Test failed due to:" + e.getMessage()); |
| } |
| } |
| |
| public void testServerConsumeFromNamedQueueInvalid() throws AMQException, URLSyntaxException, NamingException, Exception |
| { |
| try |
| { |
| Connection conn = getConnection("test", "client", "guest"); |
| |
| Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); |
| |
| conn.start(); |
| |
| sess.createConsumer(sess.createQueue("Invalid")); |
| |
| fail("Test failed as consumer was created."); |
| } |
| catch (JMSException e) |
| { |
| check403Exception(e.getLinkedException()); |
| } |
| } |
| |
| public void testServerConsumeFromTemporaryQueue() throws AMQException, URLSyntaxException, NamingException, Exception |
| { |
| try |
| { |
| Connection conn = getConnection("test", "server", "guest"); |
| |
| Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); |
| |
| conn.start(); |
| |
| sess.createConsumer(sess.createTemporaryQueue()); |
| |
| fail("Test failed as consumer was created."); |
| } |
| catch (JMSException e) |
| { |
| check403Exception(e.getLinkedException()); |
| } |
| } |
| |
| public void testServerCreateNamedQueueValid() throws JMSException, URLSyntaxException, Exception |
| { |
| try |
| { |
| Connection conn = getConnection("test", "server", "guest"); |
| |
| Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); |
| |
| conn.start(); |
| |
| //Create Temporary Queue |
| ((AMQSession<?, ?>) sess).createQueue(new AMQShortString("example.RequestQueue"), false, false, false); |
| |
| conn.close(); |
| } |
| catch (Exception e) |
| { |
| fail("Test failed due to:" + e.getMessage()); |
| } |
| } |
| |
| public void testServerCreateNamedQueueInvalid() throws JMSException, URLSyntaxException, AMQException, NamingException, Exception |
| { |
| try |
| { |
| Connection conn = getConnection("test", "server", "guest"); |
| |
| Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); |
| |
| conn.start(); |
| |
| //Create a Named Queue |
| ((AMQSession<?, ?>) sess).createQueue(new AMQShortString("IllegalQueue"), false, false, false); |
| |
| fail("Test failed as creation succeded."); |
| } |
| catch (Exception e) |
| { |
| check403Exception(e); |
| } |
| } |
| |
| public void testServerCreateTemporaryQueueInvalid() throws NamingException, Exception |
| { |
| try |
| { |
| Connection conn = getConnection("test", "server", "guest"); |
| Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); |
| |
| conn.start(); |
| |
| session.createTemporaryQueue(); |
| |
| fail("Test failed as creation succeded."); |
| } |
| catch (JMSException e) |
| { |
| check403Exception(e.getLinkedException()); |
| } |
| } |
| |
| public void testServerCreateAutoDeleteQueueInvalid() throws NamingException, JMSException, AMQException, Exception |
| { |
| try |
| { |
| Connection connection = getConnection("test", "server", "guest"); |
| |
| Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); |
| |
| connection.start(); |
| |
| ((AMQSession<?, ?>) session).createQueue(new AMQShortString("again_ensure_auto_delete_queue_for_temporary"), |
| true, false, false); |
| |
| fail("Test failed as creation succeded."); |
| } |
| catch (Exception e) |
| { |
| check403Exception(e); |
| } |
| } |
| |
| /** |
| * This test uses both the cilent and sender to validate that the Server is able to publish to a temporary queue. |
| * The reason the client must be involved is that the Server is unable to create its own Temporary Queues. |
| * |
| * @throws AMQException |
| * @throws URLSyntaxException |
| * @throws JMSException |
| */ |
| public void testServerPublishUsingTransactionSuccess() throws AMQException, URLSyntaxException, JMSException, NamingException, Exception |
| { |
| //Set up the Server |
| Connection serverConnection = getConnection("test", "server", "guest"); |
| |
| Session serverSession = serverConnection.createSession(true, Session.SESSION_TRANSACTED); |
| |
| Queue requestQueue = serverSession.createQueue("example.RequestQueue"); |
| |
| MessageConsumer server = serverSession.createConsumer(requestQueue); |
| |
| serverConnection.start(); |
| |
| //Set up the consumer |
| Connection clientConnection = getConnection("test", "client", "guest"); |
| |
| //Send a test mesage |
| Session clientSession = clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); |
| |
| Queue responseQueue = clientSession.createTemporaryQueue(); |
| |
| MessageConsumer clientResponse = clientSession.createConsumer(responseQueue); |
| |
| clientConnection.start(); |
| |
| Message request = clientSession.createTextMessage("Request"); |
| |
| assertNotNull("Response Queue is null", responseQueue); |
| |
| request.setJMSReplyTo(responseQueue); |
| |
| clientSession.createProducer(requestQueue).send(request); |
| |
| try |
| { |
| Message msg = null; |
| |
| msg = server.receive(2000); |
| |
| while (msg != null && !((TextMessage) msg).getText().equals("Request")) |
| { |
| msg = server.receive(2000); |
| } |
| |
| assertNotNull("Message not received", msg); |
| |
| assertNotNull("Reply-To is Null", msg.getJMSReplyTo()); |
| |
| MessageProducer sender = serverSession.createProducer(msg.getJMSReplyTo()); |
| |
| sender.send(serverSession.createTextMessage("Response")); |
| |
| //Send the message using a transaction as this will allow us to retrieve any errors that occur on the broker. |
| serverSession.commit(); |
| |
| //Ensure Response is received. |
| Message clientResponseMsg = clientResponse.receive(2000); |
| assertNotNull("Client did not receive response message,", clientResponseMsg); |
| assertEquals("Incorrect message received", "Response", ((TextMessage) clientResponseMsg).getText()); |
| |
| } |
| catch (Exception e) |
| { |
| fail("Test publish failed:" + e); |
| } |
| finally |
| { |
| try |
| { |
| serverConnection.close(); |
| } |
| finally |
| { |
| clientConnection.close(); |
| } |
| } |
| } |
| |
| public void testServerPublishInvalidQueueSuccess() throws AMQException, URLSyntaxException, JMSException, NamingException, Exception |
| { |
| try |
| { |
| Connection conn = getConnection("test", "server", "guest"); |
| |
| ((AMQConnection) conn).setConnectionListener(this); |
| |
| Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); |
| |
| conn.start(); |
| |
| MessageProducer sender = ((AMQSession<?, ?>) session).createProducer(null); |
| |
| Queue queue = session.createQueue("Invalid"); |
| |
| // Send a message that we will wait to be sent, this should give the broker time to close the connection |
| // before we finish this test. Message is set !immed !mand as the queue is invalid so want to test ACLs not |
| // queue existence. |
| ((org.apache.qpid.jms.MessageProducer) sender).send(queue, session.createTextMessage("test"), |
| DeliveryMode.NON_PERSISTENT, 0, 0L, false, false, true); |
| |
| // Test the connection with a valid consumer |
| // This may not work as the session may be closed before the queue or consumer creation can occur. |
| // The correct JMSexception with linked error will only occur when the close method is recevied whilst in |
| // the failover safe block |
| session.createConsumer(session.createQueue("example.RequestQueue")).close(); |
| |
| //Connection should now be closed and will throw the exception caused by the above send |
| conn.close(); |
| |
| fail("Close is not expected to succeed."); |
| } |
| catch (IllegalStateException e) |
| { |
| _logger.info("QPID-2345: Session became closed and we got that error rather than the authentication error."); |
| } |
| catch (JMSException e) |
| { |
| check403Exception(e.getLinkedException()); |
| } |
| } |
| } |