001 /*
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements. See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership. The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License. You may obtain a copy of the License at
010 *
011 * http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing,
014 * software distributed under the License is distributed on an
015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016 * KIND, either express or implied. See the License for the
017 * specific language governing permissions and limitations
018 * under the License.
019 *
020 */
021 package org.apache.qpid.server.security.access;
022
023 import org.apache.qpid.framing.AMQShortString;
024 import org.apache.qpid.framing.QueueBindBody;
025 import org.apache.qpid.framing.QueueDeclareBody;
026 import org.apache.qpid.framing.ExchangeDeclareBody;
027 import org.apache.qpid.server.queue.AMQQueue;
028 import org.apache.qpid.server.security.access.ACLPlugin.AuthzResult;
029 import org.apache.qpid.server.exchange.Exchange;
030
031 import java.util.*;
032 import java.util.concurrent.ConcurrentHashMap;
033
034 public class PrincipalPermissions
035 {
036
037 private static final Object CONSUME_QUEUES_KEY = new Object();
038 private static final Object CONSUME_TEMPORARY_KEY = new Object();
039 private static final Object CONSUME_OWN_QUEUES_ONLY_KEY = new Object();
040
041 private static final Object CREATE_QUEUES_KEY = new Object();
042 private static final Object CREATE_EXCHANGES_KEY = new Object();
043
044 private static final Object CREATE_QUEUE_TEMPORARY_KEY = new Object();
045 private static final Object CREATE_QUEUE_QUEUES_KEY = new Object();
046 private static final Object CREATE_QUEUE_EXCHANGES_KEY = new Object();
047
048 private static final Object CREATE_QUEUE_EXCHANGES_TEMPORARY_KEY = new Object();
049 private static final Object CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY = new Object();
050
051 private static final int PUBLISH_EXCHANGES_KEY = 0;
052
053 private Map _permissions;
054
055 private String _user;
056
057
058 public PrincipalPermissions(String user)
059 {
060 _user = user;
061 _permissions = new ConcurrentHashMap();
062 }
063
064 /**
065 *
066 * @param permission the type of permission to check
067 *
068 * @param parameters vararg depending on what permission was passed in
069 * ACCESS: none
070 * BIND: none
071 * CONSUME: AMQShortString queueName, Boolean temporary, Boolean ownQueueOnly
072 * CREATEQUEUE: Boolean temporary, AMQShortString queueName, AMQShortString exchangeName, AMQShortString routingKey
073 * CREATEEXCHANGE: AMQShortString exchangeName, AMQShortString Class
074 * DELETE: none
075 * PUBLISH: Exchange exchange, AMQShortString routingKey
076 * PURGE: none
077 * UNBIND: none
078 */
079 public void grant(Permission permission, Object... parameters)
080 {
081 switch (permission)
082 {
083 case ACCESS:
084 break; // This is a no-op as the existence of this PrincipalPermission object is scoped per VHost for ACCESS
085 case BIND:
086 break; // All the details are currently included in the create setup.
087 case CONSUME: // Parameters : AMQShortString queueName, Boolean Temporary, Boolean ownQueueOnly
088 Map consumeRights = (Map) _permissions.get(permission);
089
090 if (consumeRights == null)
091 {
092 consumeRights = new ConcurrentHashMap();
093 _permissions.put(permission, consumeRights);
094 }
095
096 //if we have parametsre
097 if (parameters.length > 0)
098 {
099 AMQShortString queueName = (AMQShortString) parameters[0];
100 Boolean temporary = (Boolean) parameters[1];
101 Boolean ownQueueOnly = (Boolean) parameters[2];
102
103 if (temporary)
104 {
105 consumeRights.put(CONSUME_TEMPORARY_KEY, true);
106 }
107 else
108 {
109 consumeRights.put(CONSUME_TEMPORARY_KEY, false);
110 }
111
112 if (ownQueueOnly)
113 {
114 consumeRights.put(CONSUME_OWN_QUEUES_ONLY_KEY, true);
115 }
116 else
117 {
118 consumeRights.put(CONSUME_OWN_QUEUES_ONLY_KEY, false);
119 }
120
121
122 LinkedList queues = (LinkedList) consumeRights.get(CONSUME_QUEUES_KEY);
123 if (queues == null)
124 {
125 queues = new LinkedList();
126 consumeRights.put(CONSUME_QUEUES_KEY, queues);
127 }
128
129 if (queueName != null)
130 {
131 queues.add(queueName);
132 }
133 }
134
135
136 break;
137 case CREATEQUEUE: // Parameters : Boolean temporary, AMQShortString queueName
138 // , AMQShortString exchangeName , AMQShortString routingKey
139
140 Map createRights = (Map) _permissions.get(permission);
141
142 if (createRights == null)
143 {
144 createRights = new ConcurrentHashMap();
145 _permissions.put(permission, createRights);
146
147 }
148
149 //The existence of the empty map mean permission to all.
150 if (parameters.length == 0)
151 {
152 return;
153 }
154
155 Boolean temporary = (Boolean) parameters[0];
156
157 AMQShortString queueName = parameters.length > 1 ? (AMQShortString) parameters[1] : null;
158 AMQShortString exchangeName = parameters.length > 2 ? (AMQShortString) parameters[2] : null;
159 //Set the routingkey to the specified value or the queueName if present
160 AMQShortString routingKey = parameters.length > 3 ? (AMQShortString) parameters[3] : queueName;
161
162 // Get the queues map
163 Map create_queues = (Map) createRights.get(CREATE_QUEUES_KEY);
164
165 if (create_queues == null)
166 {
167 create_queues = new ConcurrentHashMap();
168 createRights.put(CREATE_QUEUES_KEY, create_queues);
169 }
170
171 //Allow all temp queues to be created
172 create_queues.put(CREATE_QUEUE_TEMPORARY_KEY, temporary);
173
174 //Create empty list of queues
175 Map create_queues_queues = (Map) create_queues.get(CREATE_QUEUE_QUEUES_KEY);
176
177 if (create_queues_queues == null)
178 {
179 create_queues_queues = new ConcurrentHashMap();
180 create_queues.put(CREATE_QUEUE_QUEUES_KEY, create_queues_queues);
181 }
182
183 // We are granting CREATE rights to all temporary queues only
184 if (parameters.length == 1)
185 {
186 return;
187 }
188
189 // if we have a queueName then we need to store any associated exchange / rk bindings
190 if (queueName != null)
191 {
192 Map queue = (Map) create_queues_queues.get(queueName);
193 if (queue == null)
194 {
195 queue = new ConcurrentHashMap();
196 create_queues_queues.put(queueName, queue);
197 }
198
199 if (exchangeName != null)
200 {
201 queue.put(exchangeName, routingKey);
202 }
203
204 //If no exchange is specified then the presence of the queueName in the map says any exchange is ok
205 }
206
207 // Store the exchange that we are being granted rights to. This will be used as part of binding
208
209 //Lookup the list of exchanges
210 Map create_queues_exchanges = (Map) create_queues.get(CREATE_QUEUE_EXCHANGES_KEY);
211
212 if (create_queues_exchanges == null)
213 {
214 create_queues_exchanges = new ConcurrentHashMap();
215 create_queues.put(CREATE_QUEUE_EXCHANGES_KEY, create_queues_exchanges);
216 }
217
218 //if we have an exchange
219 if (exchangeName != null)
220 {
221 //Retrieve the list of permitted exchanges.
222 Map exchanges = (Map) create_queues_exchanges.get(exchangeName);
223
224 if (exchanges == null)
225 {
226 exchanges = new ConcurrentHashMap();
227 create_queues_exchanges.put(exchangeName, exchanges);
228 }
229
230 //Store the temporary setting CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY
231 exchanges.put(CREATE_QUEUE_EXCHANGES_TEMPORARY_KEY, temporary);
232
233 //Store the binding details of queue/rk for this exchange.
234 if (queueName != null)
235 {
236 //Retrieve the list of permitted routingKeys.
237 Map rKeys = (Map) exchanges.get(exchangeName);
238
239 if (rKeys == null)
240 {
241 rKeys = new ConcurrentHashMap();
242 exchanges.put(CREATE_QUEUE_EXCHANGES_ROUTINGKEYS_KEY, rKeys);
243 }
244
245 rKeys.put(queueName, routingKey);
246 }
247 }
248 break;
249 case CREATEEXCHANGE:
250 // Parameters AMQShortString exchangeName , AMQShortString Class
251 Map rights = (Map) _permissions.get(permission);
252 if (rights == null)
253 {
254 rights = new ConcurrentHashMap();
255 _permissions.put(permission, rights);
256 }
257
258 Map create_exchanges = (Map) rights.get(CREATE_EXCHANGES_KEY);
259 if (create_exchanges == null)
260 {
261 create_exchanges = new ConcurrentHashMap();
262 rights.put(CREATE_EXCHANGES_KEY, create_exchanges);
263 }
264
265 //Should perhaps error if parameters[0] is null;
266 AMQShortString name = parameters.length > 0 ? (AMQShortString) parameters[0] : null;
267 AMQShortString className = parameters.length > 1 ? (AMQShortString) parameters[1] : new AMQShortString("direct");
268
269 //Store the exchangeName / class mapping if the mapping is null
270 rights.put(name, className);
271 break;
272 case DELETE:
273 break;
274
275 case PUBLISH: // Parameters : Exchange exchange, AMQShortString routingKey
276 Map publishRights = (Map) _permissions.get(permission);
277
278 if (publishRights == null)
279 {
280 publishRights = new ConcurrentHashMap();
281 _permissions.put(permission, publishRights);
282 }
283
284 if (parameters == null || parameters.length == 0)
285 {
286 //If we have no parameters then allow publish to all destinations
287 // this is signified by having a null value for publish_exchanges
288 }
289 else
290 {
291 Map publish_exchanges = (Map) publishRights.get(PUBLISH_EXCHANGES_KEY);
292
293 if (publish_exchanges == null)
294 {
295 publish_exchanges = new ConcurrentHashMap();
296 publishRights.put(PUBLISH_EXCHANGES_KEY, publish_exchanges);
297 }
298
299
300 HashSet routingKeys = (HashSet) publish_exchanges.get(parameters[0]);
301
302 // Check to see if we have a routing key
303 if (parameters.length == 2)
304 {
305 if (routingKeys == null)
306 {
307 routingKeys = new HashSet<AMQShortString>();
308 }
309 //Add routing key to permitted publish destinations
310 routingKeys.add(parameters[1]);
311 }
312
313 // Add the updated routingkey list or null if all values allowed
314 publish_exchanges.put(parameters[0], routingKeys);
315 }
316 break;
317 case PURGE:
318 break;
319 case UNBIND:
320 break;
321 }
322
323 }
324
325 /**
326 *
327 * @param permission the type of permission to check
328 *
329 * @param parameters vararg depending on what permission was passed in
330 * ACCESS: none
331 * BIND: QueueBindBody bindmethod, Exchange exchange, AMQQueue queue, AMQShortString routingKey
332 * CONSUME: AMQQueue queue
333 * CREATEQUEUE: Boolean autodelete, AMQShortString name
334 * CREATEEXCHANGE: AMQShortString exchangeName
335 * DELETE: none
336 * PUBLISH: Exchange exchange, AMQShortString routingKey
337 * PURGE: none
338 * UNBIND: none
339 */
340 public AuthzResult authorise(Permission permission, Object... parameters)
341 {
342
343 switch (permission)
344 {
345 case ACCESS:
346 return AuthzResult.ALLOWED; // This is here for completeness but the SimpleXML ACLManager never calls it.
347 // The existence of this user specific PP can be validated in the map SimpleXML maintains.
348 case BIND: // Parameters : QueueBindMethod , Exchange , AMQQueue, AMQShortString routingKey
349
350 Exchange exchange = (Exchange) parameters[1];
351
352 AMQQueue bind_queueName = (AMQQueue) parameters[2];
353 AMQShortString routingKey = (AMQShortString) parameters[3];
354
355 //Get all Create Rights for this user
356 Map bindCreateRights = (Map) _permissions.get(Permission.CREATEQUEUE);
357
358 //Look up the Queue Creation Rights
359 Map bind_create_queues = (Map) bindCreateRights.get(CREATE_QUEUES_KEY);
360
361 //Lookup the list of queues
362 Map bind_create_queues_queues = (Map) bindCreateRights.get(CREATE_QUEUE_QUEUES_KEY);
363
364 // Check and see if we have a queue white list to check
365 if (bind_create_queues_queues != null)
366 {
367 //There a white list for queues
368 Map exchangeDetails = (Map) bind_create_queues_queues.get(bind_queueName);
369
370 if (exchangeDetails == null) //Then all queue can be bound to all exchanges.
371 {
372 return AuthzResult.ALLOWED;
373 }
374
375 // Check to see if we have a white list of routingkeys to check
376 Map rkeys = (Map) exchangeDetails.get(exchange.getName());
377
378 // if keys is null then any rkey is allowed on this exchange
379 if (rkeys == null)
380 {
381 // There is no routingkey white list
382 return AuthzResult.ALLOWED;
383 }
384 else
385 {
386 // We have routingKeys so a match must be found to allowed binding
387 Iterator keys = rkeys.keySet().iterator();
388
389 boolean matched = false;
390 while (keys.hasNext() && !matched)
391 {
392 AMQShortString rkey = (AMQShortString) keys.next();
393 if (rkey.endsWith("*"))
394 {
395 matched = routingKey.startsWith(rkey.subSequence(0, rkey.length() - 1).toString());
396 }
397 else
398 {
399 matched = routingKey.equals(rkey);
400 }
401 }
402
403
404 return (matched) ? AuthzResult.ALLOWED : AuthzResult.DENIED;
405 }
406
407
408 }
409 else
410 {
411 //There a is no white list for queues
412
413 // So can allow all queues to be bound
414 // but we should first check and see if we have a temp queue and validate that we are allowed
415 // to bind temp queues.
416
417 //Check to see if we have a temporary queue
418 if (bind_queueName.isAutoDelete())
419 {
420 // Check and see if we have an exchange white list.
421 Map bind_exchanges = (Map) bind_create_queues.get(CREATE_QUEUE_EXCHANGES_KEY);
422
423 // If the exchange exists then we must check to see if temporary queues are allowed here
424 if (bind_exchanges != null)
425 {
426 // Check to see if the requested exchange is allowed.
427 Map exchangeDetails = (Map) bind_exchanges.get(exchange.getName());
428
429 return ((Boolean) exchangeDetails.get(CREATE_QUEUE_EXCHANGES_TEMPORARY_KEY)) ? AuthzResult.ALLOWED : AuthzResult.DENIED;
430 }
431
432 //no white list so all allowed, drop through to return true below.
433 }
434
435 // not a temporary queue and no white list so all allowed.
436 return AuthzResult.ALLOWED;
437 }
438
439 case CREATEQUEUE:// Parameters : boolean autodelete, AMQShortString name
440
441 Map createRights = (Map) _permissions.get(permission);
442
443 // If there are no create rights then deny request
444 if (createRights == null)
445 {
446 return AuthzResult.DENIED;
447 }
448
449 //Look up the Queue Creation Rights
450 Map create_queues = (Map) createRights.get(CREATE_QUEUES_KEY);
451
452 //Lookup the list of queues allowed to be created
453 Map create_queues_queues = (Map) create_queues.get(CREATE_QUEUE_QUEUES_KEY);
454
455
456 AMQShortString queueName = (AMQShortString) parameters[1];
457 Boolean autoDelete = (Boolean) parameters[0];
458
459 if (autoDelete)// we have a temporary queue
460 {
461 return ((Boolean) create_queues.get(CREATE_QUEUE_TEMPORARY_KEY)) ? AuthzResult.ALLOWED : AuthzResult.DENIED;
462 }
463 else
464 {
465 // If there is a white list then check
466 if (create_queues_queues == null || create_queues_queues.containsKey(queueName))
467 {
468 return AuthzResult.ALLOWED;
469 }
470 else
471 {
472 return AuthzResult.DENIED;
473 }
474
475 }
476 case CREATEEXCHANGE:
477 Map rights = (Map) _permissions.get(permission);
478
479 AMQShortString exchangeName = (AMQShortString) parameters[0];
480
481 // If the exchange list is doesn't exist then all is allowed else
482 // check the valid exchanges
483 if (rights == null || rights.containsKey(exchangeName))
484 {
485 return AuthzResult.ALLOWED;
486 }
487 else
488 {
489 return AuthzResult.DENIED;
490 }
491 case CONSUME: // Parameters : AMQQueue
492
493 if (parameters.length == 1 && parameters[0] instanceof AMQQueue)
494 {
495 AMQQueue queue = ((AMQQueue) parameters[0]);
496 Map queuePermissions = (Map) _permissions.get(permission);
497
498 List queues = (List) queuePermissions.get(CONSUME_QUEUES_KEY);
499
500 Boolean temporayQueues = (Boolean) queuePermissions.get(CONSUME_TEMPORARY_KEY);
501 Boolean ownQueuesOnly = (Boolean) queuePermissions.get(CONSUME_OWN_QUEUES_ONLY_KEY);
502
503 // If user is allowed to publish to temporary queues and this is a temp queue then allow it.
504 if (temporayQueues)
505 {
506 if (queue.isAutoDelete())
507 // This will allow consumption from any temporary queue including ones not owned by this user.
508 // Of course the exclusivity will not be broken.
509 {
510 // if not limited to ownQueuesOnly then ok else check queue Owner.
511 return (!ownQueuesOnly || queue.getOwner().equals(_user)) ? AuthzResult.ALLOWED : AuthzResult.DENIED;
512 }
513 else
514 {
515 return AuthzResult.DENIED;
516 }
517 }
518
519 // if queues are white listed then ensure it is ok
520 if (queues != null)
521 {
522 // if no queues are listed then ALL are ok othereise it must be specified.
523 if (ownQueuesOnly)
524 {
525 if (queue.getOwner().equals(_user))
526 {
527 return (queues.size() == 0 || queues.contains(queue.getName())) ? AuthzResult.ALLOWED : AuthzResult.DENIED;
528 }
529 else
530 {
531 return AuthzResult.DENIED;
532 }
533 }
534
535 // If we are
536 return (queues.size() == 0 || queues.contains(queue.getName())) ? AuthzResult.ALLOWED : AuthzResult.DENIED;
537 }
538 }
539
540 // Can't authenticate without the right parameters
541 return AuthzResult.DENIED;
542 case DELETE:
543 break;
544
545 case PUBLISH: // Parameters : Exchange exchange, AMQShortString routingKey
546 Map publishRights = (Map) _permissions.get(permission);
547
548 if (publishRights == null)
549 {
550 return AuthzResult.DENIED;
551 }
552
553 Map exchanges = (Map) publishRights.get(PUBLISH_EXCHANGES_KEY);
554
555 // Having no exchanges listed gives full publish rights to all exchanges
556 if (exchanges == null)
557 {
558 return AuthzResult.ALLOWED;
559 }
560 // Otherwise exchange must be listed in the white list
561
562 // If the map doesn't have the exchange then it isn't allowed
563 if (!exchanges.containsKey(((Exchange) parameters[0]).getName()))
564 {
565 return AuthzResult.DENIED;
566 }
567 else
568 {
569
570 // Get valid routing keys
571 HashSet routingKeys = (HashSet) exchanges.get(((Exchange)parameters[0]).getName());
572
573 // Having no routingKeys in the map then all are allowed.
574 if (routingKeys == null)
575 {
576 return AuthzResult.ALLOWED;
577 }
578 else
579 {
580 // We have routingKeys so a match must be found to allowed binding
581 Iterator keys = routingKeys.iterator();
582
583
584 AMQShortString publishRKey = (AMQShortString)parameters[1];
585
586 boolean matched = false;
587 while (keys.hasNext() && !matched)
588 {
589 AMQShortString rkey = (AMQShortString) keys.next();
590
591 if (rkey.endsWith("*"))
592 {
593 matched = publishRKey.startsWith(rkey.subSequence(0, rkey.length() - 1));
594 }
595 else
596 {
597 matched = publishRKey.equals(rkey);
598 }
599 }
600 return (matched) ? AuthzResult.ALLOWED : AuthzResult.DENIED;
601 }
602 }
603 case PURGE:
604 break;
605 case UNBIND:
606 break;
607
608 }
609
610 return AuthzResult.DENIED;
611 }
612 }
|