SimpleACLTest.java
001 /*
002  *  Licensed to the Apache Software Foundation (ASF) under one
003  *  or more contributor license agreements.  See the NOTICE file
004  *  distributed with this work for additional information
005  *  regarding copyright ownership.  The ASF licenses this file
006  *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008  *  with the License.  You may obtain a copy of the License at
009  *
010  *    http://www.apache.org/licenses/LICENSE-2.0
011  *
012  *  Unless required by applicable law or agreed to in writing,
013  *  software distributed under the License is distributed on an
014  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015  *  KIND, either express or implied.  See the License for the
016  *  specific language governing permissions and limitations
017  *  under the License.
018  *
019  *
020  */
021 
022 package org.apache.qpid.server.security.acl;
023 
024 import junit.framework.TestCase;
025 import org.apache.qpid.client.transport.TransportConnection;
026 import org.apache.qpid.client.*;
027 import org.apache.qpid.framing.AMQShortString;
028 import org.apache.qpid.server.registry.ApplicationRegistry;
029 import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry;
030 import org.apache.qpid.AMQException;
031 import org.apache.qpid.test.utils.QpidTestCase;
032 import org.apache.qpid.jms.ConnectionListener;
033 import org.apache.qpid.url.URLSyntaxException;
034 
035 import javax.jms.*;
036 import javax.jms.IllegalStateException;
037 import java.io.File;
038 
039 public class SimpleACLTest extends QpidTestCase implements ConnectionListener
040 {
041     private String BROKER = "vm://:1";//"tcp://localhost:5672";
042 
043     public void setUp() throws Exception
044     {
045         //Shutdown the QTC broker
046         stopBroker();
047 
048         // Initialise ACLs.
049         final String QpidExampleHome = System.getProperty("QPID_EXAMPLE_HOME");
050         final File defaultaclConfigFile = new File(QpidExampleHome, "etc/acl.config.xml");
051 
052         if (!defaultaclConfigFile.exists())
053         {
054             System.err.println("Configuration file not found:" + defaultaclConfigFile);
055             fail("Configuration file not found:" + defaultaclConfigFile);
056         }
057 
058         if (System.getProperty("QPID_HOME"== null)                                                                                            
059         {
060             fail("QPID_HOME not set");
061         }
062 
063         ConfigurationFileApplicationRegistry config = new ConfigurationFileApplicationRegistry(defaultaclConfigFile);
064         ApplicationRegistry.initialise(config, 1);
065         TransportConnection.createVMBroker(1);
066     }
067 
068     public void tearDown()
069     {
070         TransportConnection.killAllVMBrokers();
071         ApplicationRegistry.remove(1);
072     }
073 
074     public String createConnectionString(String username, String password, String broker)
075     {
076 
077         return "amqp://" + username + ":" + password + "@clientid/test?brokerlist='" + broker + "?retries='0''";
078     }
079 
080     public void testAccessAuthorized() throws AMQException, URLSyntaxException
081     {
082         try
083         {
084             Connection conn = createConnection("client""guest");
085 
086             Session sesh = conn.createSession(true, Session.SESSION_TRANSACTED);
087 
088             conn.start();
089 
090             //Do something to show connection is active.
091             sesh.rollback();
092 
093             conn.close();
094         }
095         catch (Exception e)
096         {
097             fail("Connection was not created due to:" + e.getMessage());
098         }
099     }
100 
101     public void testAccessNoRights() throws URLSyntaxException, JMSException
102     {
103         try
104         {
105             Connection conn = createConnection("guest""guest");
106 
107             //Attempt to do do things to test connection.
108             Session sesh = conn.createSession(true, Session.SESSION_TRANSACTED);
109             conn.start();
110             sesh.rollback();
111 
112             conn.close();
113             fail("Connection was created.");
114         }
115         catch (AMQException amqe)
116         {
117             Throwable cause = amqe.getCause();
118             assertEquals("Exception was wrong type", AMQAuthenticationException.class, cause.getClass());
119             assertEquals("Incorrect error code thrown"403((AMQAuthenticationExceptioncause).getErrorCode().getCode());
120         }
121     }
122 
123     public void testClientConsumeFromTempQueueValid() throws AMQException, URLSyntaxException
124     {
125         try
126         {
127             Connection conn = createConnection("client""guest");
128 
129             Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
130 
131             conn.start();
132 
133             sesh.createConsumer(sesh.createTemporaryQueue());
134 
135             conn.close();
136         }
137         catch (Exception e)
138         {
139             fail("Test failed due to:" + e.getMessage());
140         }
141     }
142 
143     public void testClientConsumeFromNamedQueueInvalid() throws AMQException, URLSyntaxException
144     {
145         try
146         {
147             Connection conn = createConnection("client""guest");
148 
149             //Prevent Failover
150             ((AMQConnectionconn).setConnectionListener(this);
151 
152             Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
153 
154             conn.start();
155 
156             sesh.createConsumer(sesh.createQueue("IllegalQueue"));
157             fail("Test failed as consumer was created.");
158             //conn will be automatically closed
159         }
160         catch (JMSException e)
161         {
162             Throwable cause = e.getLinkedException();
163 
164             assertNotNull("There was no liked exception", cause);
165             assertEquals("Wrong linked exception type", AMQAuthenticationException.class, cause.getClass());
166             assertEquals("Incorrect error code received"403((AMQAuthenticationExceptioncause).getErrorCode().getCode());
167         }
168     }
169 
170     public void testClientCreateTemporaryQueue() throws JMSException, URLSyntaxException
171     {
172         try
173         {
174             Connection conn = createConnection("client""guest");
175 
176             Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
177 
178             conn.start();
179 
180             //Create Temporary Queue  - can't use the createTempQueue as QueueName is null.
181             ((AMQSessionsesh).createQueue(new AMQShortString("doesnt_matter_as_autodelete_means_tmp"),
182                                             true, false, false);
183 
184             conn.close();
185         }
186         catch (Exception e)
187         {
188             fail("Test failed due to:" + e.getMessage());
189         }
190     }
191 
192     public void testClientCreateNamedQueue() throws JMSException, URLSyntaxException, AMQException
193     {
194         try
195         {
196             Connection conn = createConnection("client""guest");
197 
198             Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
199 
200             conn.start();
201 
202             //Create a Named Queue
203             ((AMQSessionsesh).createQueue(new AMQShortString("IllegalQueue"), false, false, false);
204 
205             fail("Test failed as Queue creation succeded.");
206             //conn will be automatically closed
207         }
208         catch (AMQAuthenticationException amqe)
209         {
210             assertEquals("Incorrect error code thrown"403((AMQAuthenticationExceptionamqe).getErrorCode().getCode());
211         }
212     }
213 
214     public void testClientPublishUsingTransactionSuccess() throws AMQException, URLSyntaxException
215     {
216         try
217         {
218             Connection conn = createConnection("client""guest");
219 
220             ((AMQConnectionconn).setConnectionListener(this);
221 
222             Session sesh = conn.createSession(true, Session.SESSION_TRANSACTED);
223 
224             conn.start();
225 
226             MessageProducer sender = sesh.createProducer(sesh.createQueue("example.RequestQueue"));
227 
228             sender.send(sesh.createTextMessage("test"));
229 
230             //Send the message using a transaction as this will allow us to retrieve any errors that occur on the broker.
231             sesh.commit();
232 
233             conn.close();
234         }
235         catch (Exception e)
236         {
237             fail("Test publish failed:" + e);
238         }
239     }
240 
241     public void testClientPublishValidQueueSuccess() throws AMQException, URLSyntaxException
242     {
243         try
244         {
245             Connection conn = createConnection("client""guest");
246 
247             ((AMQConnectionconn).setConnectionListener(this);
248 
249             Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
250 
251             conn.start();
252 
253             MessageProducer sender = ((AMQSessionsesh).createProducer(null);
254 
255             Queue queue = sesh.createQueue("example.RequestQueue");
256 
257             // Send a message that we will wait to be sent, this should give the broker time to process the msg
258             // before we finish this test. Message is set !immed !mand as the queue is invalid so want to test ACLs not
259             // queue existence.
260             ((org.apache.qpid.jms.MessageProducersender).send(queue, sesh.createTextMessage("test"),
261                                                                 DeliveryMode.NON_PERSISTENT, 00L, false, false, true);
262 
263             conn.close();
264         }
265         catch (Exception e)
266         {
267             fail("Test publish failed:" + e);
268         }
269     }
270 
271     public void testClientPublishInvalidQueueSuccess() throws AMQException, URLSyntaxException, JMSException
272     {
273         try
274         {
275             Connection conn = createConnection("client""guest");
276 
277             ((AMQConnectionconn).setConnectionListener(this);
278 
279             Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
280 
281             conn.start();
282 
283             MessageProducer sender = ((AMQSessionsession).createProducer(null);
284 
285             Queue queue = session.createQueue("Invalid");
286 
287             // Send a message that we will wait to be sent, this should give the broker time to close the connection
288             // before we finish this test. Message is set !immed !mand as the queue is invalid so want to test ACLs not
289             // queue existence.
290             ((org.apache.qpid.jms.MessageProducersender).send(queue, session.createTextMessage("test"),
291                                                                 DeliveryMode.NON_PERSISTENT, 00L, false, false, true);
292 
293             // Test the connection with a valid consumer
294             // This may fail as the session may be closed before the queue or the consumer created.
295             Queue temp = session.createTemporaryQueue();
296 
297             session.createConsumer(temp).close();
298 
299             //Connection should now be closed and will throw the exception caused by the above send
300             conn.close();
301 
302             fail("Close is not expected to succeed.");
303         }
304         catch (JMSException e)
305         {
306             Throwable cause = e.getLinkedException();
307             if (!(cause instanceof AMQAuthenticationException))
308             {
309                 e.printStackTrace();
310             }
311             assertEquals("Incorrect exception", AMQAuthenticationException.class, cause.getClass());
312             assertEquals("Incorrect error code thrown"403((AMQAuthenticationExceptioncause).getErrorCode().getCode());
313         }
314     }
315 
316     public void testServerConsumeFromNamedQueueValid() throws AMQException, URLSyntaxException
317     {
318         try
319         {
320             Connection conn = createConnection("server""guest");
321 
322             Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
323 
324             conn.start();
325 
326             sesh.createConsumer(sesh.createQueue("example.RequestQueue"));
327 
328             conn.close();
329         }
330         catch (Exception e)
331         {
332             fail("Test failed due to:" + e.getMessage());
333         }
334     }
335 
336     public void testServerConsumeFromNamedQueueInvalid() throws AMQException, URLSyntaxException
337     {
338         try
339         {                                                      
340             Connection conn = createConnection("client""guest");
341 
342             Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
343 
344             conn.start();
345 
346             sesh.createConsumer(sesh.createQueue("Invalid"));
347 
348             fail("Test failed as consumer was created.");
349             //conn will be automatically closed
350         }
351         catch (JMSException e)
352         {
353             Throwable cause = e.getLinkedException();
354 
355             assertNotNull("There was no liked exception", cause);
356             assertEquals("Wrong linked exception type", AMQAuthenticationException.class, cause.getClass());
357             assertEquals("Incorrect error code received"403((AMQAuthenticationExceptioncause).getErrorCode().getCode());
358         }
359     }
360 
361     public void testServerConsumeFromTemporaryQueue() throws AMQException, URLSyntaxException
362     {
363         try
364         {
365             Connection conn = createConnection("server","guest");
366 
367             Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
368 
369             conn.start();
370 
371             sesh.createConsumer(sesh.createTemporaryQueue());
372             fail("Test failed as consumer was created.");
373             //conn will be automatically closed
374         }
375         catch (JMSException e)
376         {
377             Throwable cause = e.getLinkedException();
378 
379             assertNotNull("There was no liked exception", cause);
380             assertEquals("Wrong linked exception type", AMQAuthenticationException.class, cause.getClass());
381             assertEquals("Incorrect error code received"403((AMQAuthenticationExceptioncause).getErrorCode().getCode());
382         }
383     }
384 
385     private Connection createConnection(String username, String passwordthrows AMQException
386     {
387         AMQConnection connection = null;
388         try
389         {
390             connection = new AMQConnection(createConnectionString(username, password, BROKER));
391         }
392         catch (URLSyntaxException e)
393         {
394             // This should never happen as we generate the URLs.
395             fail(e.getMessage());
396         }
397 
398         //Prevent Failover
399         connection.setConnectionListener(this);
400 
401         return (Connection)connection;
402     }
403 
404     public void testServerCreateNamedQueueValid() throws JMSException, URLSyntaxException
405     {
406         try
407         {
408             Connection conn = createConnection("server""guest");
409 
410             Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
411 
412             conn.start();
413 
414             //Create Temporary Queue
415             ((AMQSessionsesh).createQueue(new AMQShortString("example.RequestQueue"), false, false, false);
416 
417             conn.close();
418         }
419         catch (Exception e)
420         {
421             fail("Test failed due to:" + e.getMessage());
422         }
423     }
424 
425     public void testServerCreateNamedQueueInvalid() throws JMSException, URLSyntaxException, AMQException
426     {
427         try
428         {
429             Connection conn = createConnection("server""guest");
430 
431             Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
432 
433             conn.start();
434 
435             //Create a Named Queue
436             ((AMQSessionsesh).createQueue(new AMQShortString("IllegalQueue"), false, false, false);
437 
438             fail("Test failed as creation succeded.");
439             //conn will be automatically closed
440         }
441         catch (AMQAuthenticationException amqe)
442         {
443             assertEquals("Incorrect error code thrown"403, amqe.getErrorCode().getCode());
444         }
445     }
446 
447     public void testServerCreateTemporaryQueueInvalid() throws JMSException, URLSyntaxException, AMQException
448     {
449         try
450         {
451             Connection conn = createConnection("server""guest");
452 
453             Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
454 
455             conn.start();
456 
457             session.createTemporaryQueue();
458                     
459             fail("Test failed as creation succeded.");
460             //conn will be automatically closed
461         }
462         catch (JMSException e)
463         {
464             Throwable cause = e.getLinkedException();
465 
466             assertNotNull("There was no liked exception", cause);
467             assertEquals("Wrong linked exception type", AMQAuthenticationException.class, cause.getClass());
468             assertEquals("Incorrect error code received"403((AMQAuthenticationExceptioncause).getErrorCode().getCode());
469         }
470     }
471 
472     public void testServerCreateAutoDeleteQueueInvalid() throws JMSException, URLSyntaxException, AMQException
473     {
474         Connection connection = null;
475         try
476         {
477             connection = createConnection("server""guest");
478 
479             Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
480 
481             connection.start();
482 
483             ((AMQSessionsession).createQueue(new AMQShortString("again_ensure_auto_delete_queue_for_temporary"),
484                                             true, false, false);
485 
486             fail("Test failed as creation succeded.");
487             //connection will be automatically closed
488         }
489         catch (AMQAuthenticationException amqe)
490         {
491             assertEquals("Incorrect error code thrown"403, amqe.getErrorCode().getCode());
492         }       
493     }
494 
495     /**
496      * This test uses both the cilent and sender to validate that the Server is able to publish to a temporary queue.
497      * The reason the client must be in volved is that the Serve is unable to create its own Temporary Queues.
498      *
499      @throws AMQException
500      @throws URLSyntaxException
501      @throws JMSException
502      */
503     public void testServerPublishUsingTransactionSuccess() throws AMQException, URLSyntaxException, JMSException
504     {
505         //Set up the Server
506         Connection serverConnection = createConnection("server""guest");
507 
508         ((AMQConnectionserverConnection).setConnectionListener(this);
509 
510         Session serverSession = serverConnection.createSession(true, Session.SESSION_TRANSACTED);
511 
512         Queue requestQueue = serverSession.createQueue("example.RequestQueue");
513 
514         MessageConsumer server = serverSession.createConsumer(requestQueue);
515 
516         serverConnection.start();
517 
518         //Set up the consumer
519         Connection clientConnection = createConnection("client""guest");
520 
521         //Send a test mesage
522         Session clientSession = clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
523 
524         Queue responseQueue = clientSession.createTemporaryQueue();
525 
526         MessageConsumer clientResponse = clientSession.createConsumer(responseQueue);
527 
528         clientConnection.start();
529 
530         Message request = clientSession.createTextMessage("Request");
531 
532         assertNotNull("Response Queue is null", responseQueue);
533 
534         request.setJMSReplyTo(responseQueue);
535 
536         clientSession.createProducer(requestQueue).send(request);
537 
538         try
539         {
540             Message msg = null;
541 
542             msg = server.receive(2000);
543 
544             while (msg != null && !((TextMessagemsg).getText().equals("Request"))
545             {
546                 msg = server.receive(2000);
547             }
548 
549             assertNotNull("Message not received", msg);
550 
551             assertNotNull("Reply-To is Null", msg.getJMSReplyTo());
552 
553             MessageProducer sender = serverSession.createProducer(msg.getJMSReplyTo());
554 
555             sender.send(serverSession.createTextMessage("Response"));
556 
557             //Send the message using a transaction as this will allow us to retrieve any errors that occur on the broker.
558             serverSession.commit();
559 
560 
561 
562             //Ensure Response is received.
563             Message clientResponseMsg = clientResponse.receive(2000);
564             assertNotNull("Client did not receive response message,", clientResponseMsg);
565             assertEquals("Incorrect message received""Response"((TextMessageclientResponseMsg).getText());
566 
567         }
568         catch (Exception e)
569         {
570             fail("Test publish failed:" + e);
571         }
572         finally
573         {
574             try
575             {
576                 serverConnection.close();
577             }
578             finally
579             {
580                 clientConnection.close();
581             }
582         }
583     }
584 
585     public void testServerPublishInvalidQueueSuccess() throws AMQException, URLSyntaxException, JMSException
586     {
587         try
588         {
589             Connection conn = createConnection("server""guest");
590 
591             ((AMQConnectionconn).setConnectionListener(this);
592 
593             Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
594 
595             conn.start();
596 
597             MessageProducer sender = ((AMQSessionsession).createProducer(null);
598 
599             Queue queue = session.createQueue("Invalid");
600 
601             // Send a message that we will wait to be sent, this should give the broker time to close the connection
602             // before we finish this test. Message is set !immed !mand as the queue is invalid so want to test ACLs not
603             // queue existence.
604             ((org.apache.qpid.jms.MessageProducersender).send(queue, session.createTextMessage("test"),
605                                                                 DeliveryMode.NON_PERSISTENT, 00L, false, false, true);
606 
607             // Test the connection with a valid consumer
608             // This may not work as the session may be closed before the queue or consumer creation can occur.
609             // The correct JMSexception with linked error will only occur when the close method is recevied whilst in
610             // the failover safe block
611             session.createConsumer(session.createQueue("example.RequestQueue")).close();
612 
613             //Connection should now be closed and will throw the exception caused by the above send
614             conn.close();
615 
616             fail("Close is not expected to succeed.");
617         }
618         catch (JMSException e)
619         {
620             Throwable cause = e.getLinkedException();
621 
622             assertEquals("Incorrect exception", AMQAuthenticationException.class, cause.getClass());
623             assertEquals("Incorrect error code thrown"403((AMQAuthenticationExceptioncause).getErrorCode().getCode());
624         }
625     }
626 
627     // Connection Listener Interface - Used here to block failover
628 
629     public void bytesSent(long count)
630     {
631     }
632 
633     public void bytesReceived(long count)
634     {
635     }
636 
637     public boolean preFailover(boolean redirect)
638     {
639         //Prevent failover.
640         return false;
641     }
642 
643     public boolean preResubscribe()
644     {
645         return false;
646     }
647 
648     public void failoverComplete()
649     {
650     }
651 }