PrincipalPermissions.java
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 = (AMQShortStringparameters[0];
100                     Boolean temporary = (Booleanparameters[1];
101                     Boolean ownQueueOnly = (Booleanparameters[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 = (LinkedListconsumeRights.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 = (Booleanparameters[0];
156 
157                 AMQShortString queueName = parameters.length > (AMQShortStringparameters[1null;
158                 AMQShortString exchangeName = parameters.length > (AMQShortStringparameters[2null;
159                 //Set the routingkey to the specified value or the queueName if present
160                 AMQShortString routingKey = parameters.length > (AMQShortStringparameters[3: queueName;
161 
162                 // Get the queues map
163                 Map create_queues = (MapcreateRights.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 = (Mapcreate_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 = (Mapcreate_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 = (Mapcreate_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 = (Mapcreate_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 = (Mapexchanges.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 = (Maprights.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 > (AMQShortStringparameters[0null;
267                 AMQShortString className = parameters.length > (AMQShortStringparameters[1new 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 = (MappublishRights.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 = (HashSetpublish_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 = (Exchangeparameters[1];
351 
352                 AMQQueue bind_queueName = (AMQQueueparameters[2];
353                 AMQShortString routingKey = (AMQShortStringparameters[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 = (MapbindCreateRights.get(CREATE_QUEUES_KEY);
360 
361                 //Lookup the list of queues
362                 Map bind_create_queues_queues = (MapbindCreateRights.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 = (Mapbind_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 = (MapexchangeDetails.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 = (AMQShortStringkeys.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 = (Mapbind_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 = (Mapbind_exchanges.get(exchange.getName());
428 
429                             return ((BooleanexchangeDetails.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 = (MapcreateRights.get(CREATE_QUEUES_KEY);
451 
452                 //Lookup the list of queues allowed to be created
453                 Map create_queues_queues = (Mapcreate_queues.get(CREATE_QUEUE_QUEUES_KEY);
454 
455 
456                 AMQShortString queueName = (AMQShortStringparameters[1];
457                 Boolean autoDelete = (Booleanparameters[0];
458 
459                 if (autoDelete)// we have a temporary queue
460                 {
461                     return ((Booleancreate_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 = (AMQShortStringparameters[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 == && parameters[0instanceof AMQQueue)
494                 {
495                     AMQQueue queue = ((AMQQueueparameters[0]);
496                     Map queuePermissions = (Map_permissions.get(permission);
497 
498                     List queues = (ListqueuePermissions.get(CONSUME_QUEUES_KEY);
499 
500                     Boolean temporayQueues = (BooleanqueuePermissions.get(CONSUME_TEMPORARY_KEY);
501                     Boolean ownQueuesOnly = (BooleanqueuePermissions.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() == || 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() == || 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 = (MappublishRights.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(((Exchangeparameters[0]).getName()))
564                 {
565                     return AuthzResult.DENIED;
566                 }
567                 else
568                 {
569 
570                     // Get valid routing keys
571                     HashSet routingKeys = (HashSetexchanges.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 = (AMQShortStringkeys.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 }