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, ((AMQAuthenticationException) cause).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 ((AMQConnection) conn).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, ((AMQAuthenticationException) cause).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 ((AMQSession) sesh).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 ((AMQSession) sesh).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, ((AMQAuthenticationException) amqe).getErrorCode().getCode());
211 }
212 }
213
214 public void testClientPublishUsingTransactionSuccess() throws AMQException, URLSyntaxException
215 {
216 try
217 {
218 Connection conn = createConnection("client", "guest");
219
220 ((AMQConnection) conn).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 ((AMQConnection) conn).setConnectionListener(this);
248
249 Session sesh = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
250
251 conn.start();
252
253 MessageProducer sender = ((AMQSession) sesh).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.MessageProducer) sender).send(queue, sesh.createTextMessage("test"),
261 DeliveryMode.NON_PERSISTENT, 0, 0L, 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 ((AMQConnection) conn).setConnectionListener(this);
278
279 Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
280
281 conn.start();
282
283 MessageProducer sender = ((AMQSession) session).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.MessageProducer) sender).send(queue, session.createTextMessage("test"),
291 DeliveryMode.NON_PERSISTENT, 0, 0L, 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, ((AMQAuthenticationException) cause).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, ((AMQAuthenticationException) cause).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, ((AMQAuthenticationException) cause).getErrorCode().getCode());
382 }
383 }
384
385 private Connection createConnection(String username, String password) throws 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 ((AMQSession) sesh).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 ((AMQSession) sesh).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, ((AMQAuthenticationException) cause).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 ((AMQSession) session).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 ((AMQConnection) serverConnection).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 && !((TextMessage) msg).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", ((TextMessage) clientResponseMsg).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 ((AMQConnection) conn).setConnectionListener(this);
592
593 Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
594
595 conn.start();
596
597 MessageProducer sender = ((AMQSession) session).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.MessageProducer) sender).send(queue, session.createTextMessage("test"),
605 DeliveryMode.NON_PERSISTENT, 0, 0L, 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, ((AMQAuthenticationException) cause).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 }
|