KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mmbase > security > implementation > context > ContextAuthorization


1 /*
2
3 This software is OSI Certified Open Source Software.
4 OSI Certified is a certification mark of the Open Source Initiative.
5
6 The license (Mozilla version 1.0) can be read at the MMBase site.
7 See http://www.MMBase.org/license
8
9 */

10 package org.mmbase.security.implementation.context;
11
12 import org.mmbase.bridge.Query;
13 import org.mmbase.cache.Cache;
14 import org.mmbase.storage.search.*;
15 import java.util.*;
16
17 import org.w3c.dom.*;
18 import org.w3c.dom.traversal.NodeIterator;
19 import org.xml.sax.InputSource JavaDoc;
20 import org.apache.xpath.XPathAPI;
21
22 import org.mmbase.module.core.MMObjectNode;
23 import org.mmbase.security.*;
24 import org.mmbase.security.SecurityException; // must be imported explicity, because it is also in
25
// java.lang
26
import org.mmbase.util.logging.Logger;
27 import org.mmbase.util.logging.Logging;
28
29 /**
30  * Authorization based on a XML-configuration file. The XML file contains users, groups and
31  * contexts. Contextes provide rights to users and/or groups and are identified by a string (which
32  * is stored in the owner field).
33  *
34  * @author Eduard Witteveen
35  * @author Pierre van Rooden
36  * @author Michiel Meeuwissen
37  * @version $Id: ContextAuthorization.java,v 1.40 2005/10/17 15:29:19 michiel Exp $
38  * @see ContextAuthentication
39  */

40 public class ContextAuthorization extends Authorization {
41     private static final Logger log = Logging.getLoggerInstance(ContextAuthorization.class);
42     private Document document;
43     private ContextCache cache = new ContextCache();
44
45     protected Cache allowingContextsCache = new Cache(200) { // 200 users.
46
public String JavaDoc getName() { return "CS:AllowingContextsCache"; }
47             public String JavaDoc getDescription() { return "Links user id to a set of contexts"; }
48         };
49
50     private int maxContextsInQuery = 50; // must be configurable
51

52     /** contains elements of type = Operation */
53     private Set globalAllowedOperations = new HashSet();
54
55     private Map replaceNotFound = new HashMap();
56     private Map userDefaultContexts = new HashMap();
57     private SortedSet allContexts;
58
59     protected void load() {
60         log.debug("using: '" + configResource + "' as config file for authentication");
61         try {
62             InputSource JavaDoc in = MMBaseCopConfig.securityLoader.getInputSource(configResource);
63             // clear the cache of unfound contexts
64
replaceNotFound.clear();
65             allowingContextsCache.clear();
66             // clear the cache of user default contexts
67
userDefaultContexts.clear();
68             // reload the security xml document
69
document = org.mmbase.util.XMLBasicReader.getDocumentBuilder(this.getClass()).parse(in);
70             getGlobalAllowedOperations();
71             setAllContexts();
72         } catch(org.xml.sax.SAXException JavaDoc se) {
73             log.error("error parsing file :"+configResource);
74             String JavaDoc message = "error loading configfile :'" + configResource + "'("+se + "->"+se.getMessage()+"("+se.getMessage()+"))";
75             log.error(message);
76             log.error(Logging.stackTrace(se));
77             throw new SecurityException JavaDoc(message);
78         } catch(java.io.IOException JavaDoc ioe) {
79             log.error("error parsing file :"+configResource);
80             log.error(Logging.stackTrace(ioe));
81             throw new SecurityException JavaDoc("error loading configfile :'"+configResource+"'("+ioe+")" );
82         }
83         log.debug("loaded: '" + configResource + "' as config file for authorization");
84     }
85
86     public String JavaDoc getDefaultContext(UserContext user) throws SecurityException JavaDoc {
87         String JavaDoc defaultContext = (String JavaDoc)userDefaultContexts.get(user);
88         if (defaultContext == null) {
89             String JavaDoc xpath = "/contextconfig/accounts/user[@name='"+user.getIdentifier()+"']";
90             Node found;
91             try {
92                 log.debug("going to execute the query:" + xpath + " on file : " + configResource);
93                 found = XPathAPI.selectSingleNode(document, xpath);
94             } catch(javax.xml.transform.TransformerException JavaDoc te) {
95                 log.error("error executing query: '"+xpath+"' on file: '"+configResource+"'" );
96                 log.error( Logging.stackTrace(te));
97                 throw new SecurityException JavaDoc("error executing query: '"+xpath+"' on file: '"+configResource+"'");
98             }
99             if (found == null) {
100                 throw new SecurityException JavaDoc("Could not find user " + user.getIdentifier() + " in context security config file (" + configResource + ")") ;
101             }
102
103             NamedNodeMap nnm = found.getAttributes();
104             Node contextNode = nnm.getNamedItem("context");
105             defaultContext = contextNode.getNodeValue();
106             userDefaultContexts.put(user,defaultContext);
107         }
108         if (log.isDebugEnabled()) {
109             log.debug("user with name: " + user + " has the default context: " + defaultContext);
110         }
111         return defaultContext;
112     }
113
114     public void create(UserContext user, int nodeNumber) throws SecurityException JavaDoc {
115         if (log.isDebugEnabled()) {
116             log.debug("create on node #" + nodeNumber + " by user: " + user);
117         }
118         String JavaDoc defaultContext = getDefaultContext(user);
119         setContext(user, nodeNumber, defaultContext);
120     }
121
122     public void update(UserContext user, int nodeNumber) throws SecurityException JavaDoc {
123         if (log.isDebugEnabled()) {
124             log.debug("update on node #" + nodeNumber+" by user: " + user);
125         }
126     }
127
128     public void remove(UserContext user, int nodeNumber) throws SecurityException JavaDoc{
129         if (log.isDebugEnabled()) {
130             log.debug("remove on node #" + nodeNumber + " by user: " + user);
131         }
132     }
133
134     public void setContext(UserContext user, int nodeNumber, String JavaDoc context) throws SecurityException JavaDoc {
135         // notify the log
136
if (log.isDebugEnabled()) {
137             log.debug("set context on node #"+nodeNumber+" by user: " + user + " to " + context );
138         }
139         // don't even bother if the context was already set.
140
MMObjectNode node = getMMNode(nodeNumber);
141         if (node.getStringValue("owner").equals(context)) return;
142
143         // check if is a valid context for us..
144
Set possible = getPossibleContexts(user, nodeNumber);
145         if(!possible.contains(context)) {
146             String JavaDoc msg = "could not set the context to "+context+" for node #"+nodeNumber+" by user: " +user;
147             log.error(msg);
148             throw new SecurityException JavaDoc(msg);
149         }
150
151         // check if this operation is allowed? (should also be done somewhere else, but we can never be sure enough)
152
verify(user, nodeNumber, Operation.CHANGE_CONTEXT);
153
154         // well now really set it...
155
node.setValue("owner", context);
156         node.commit();
157         if (log.isDebugEnabled()) {
158             log.debug("changed context settings of node #"+nodeNumber+" to context: "+context+ " by user: " +user);
159         }
160     }
161
162     public String JavaDoc getContext(UserContext user, int nodeNumber) throws SecurityException JavaDoc {
163         // notify the log
164
if (log.isDebugEnabled()) {
165             log.debug("get context on node #" + nodeNumber + " by user: " + user);
166         }
167
168         // check if this operation is allowed? (should also be done somewhere else, but we can never be sure enough)
169
verify(user, nodeNumber, Operation.READ);
170
171         // and get the value...
172
MMObjectNode node = getMMNode(nodeNumber);
173         return node.getStringValue("owner");
174     }
175
176     private void setAllContexts() throws SecurityException JavaDoc {
177         allContexts = new TreeSet();
178         String JavaDoc xpath = "/contextconfig/contexts/context";
179         log.trace("going to execute the query:" + xpath );
180         NodeIterator found;
181         try {
182             found = XPathAPI.selectNodeIterator(document, xpath);
183         } catch(javax.xml.transform.TransformerException JavaDoc te) {
184             log.error("error executing query: '" + xpath + "' ");
185             log.error( Logging.stackTrace(te));
186             throw new SecurityException JavaDoc("error executing query: '" + xpath +"' ");
187         }
188         Node context;
189         for(context = found.nextNode(); context != null; context = found.nextNode()) {
190             NamedNodeMap nnm = context.getAttributes();
191             Node contextNameNode = nnm.getNamedItem("name");
192             allContexts.add(contextNameNode.getNodeValue());
193         }
194     }
195
196     public Set getPossibleContexts(UserContext user, int nodeNumber) throws SecurityException JavaDoc {
197         if (log.isDebugEnabled()) {
198             log.debug("get possible context on node #" + nodeNumber + " by user: " + user);
199         }
200
201         // check if this operation is allowed? (should also be done somewhere else, but we can never be sure enough)
202
// TODO: research if we maybe better could use WRITE or CHANGE_CONTEXT as rights for this operation...
203
verify(user, nodeNumber, Operation.READ);
204
205         // retrieve the current context..
206
String JavaDoc currentContext = getContext(user, nodeNumber);
207         synchronized(replaceNotFound) {
208             if(replaceNotFound.containsKey(currentContext)) {
209                 currentContext = (String JavaDoc)replaceNotFound.get(currentContext);
210             }
211         }
212
213         Set list;
214         synchronized(cache) {
215             list = cache.contextGet(currentContext);
216             if(list != null) {
217                 log.debug("cache hit");
218                 return list;
219             }
220             list = new HashSet();
221         }
222
223         // possible contextes are dependeding of the context they're in...
224
String JavaDoc xpath = "/contextconfig/contexts/context[@name='"+currentContext+"']/possible";
225         log.debug("going to execute the query:" + xpath );
226         NodeIterator found;
227         try {
228             found = XPathAPI.selectNodeIterator(document, xpath);
229         } catch(javax.xml.transform.TransformerException JavaDoc te) {
230             log.error("error executing query: '"+xpath+"' ");
231             log.error( Logging.stackTrace(te));
232             throw new SecurityException JavaDoc("error executing query: '"+xpath+"' ");
233         }
234         Node context;
235         for(context = found.nextNode(); context != null; context = found.nextNode()) {
236             NamedNodeMap nnm = context.getAttributes();
237             Node contextNameNode = nnm.getNamedItem("context");
238             list.add(contextNameNode.getNodeValue());
239             if (log.isDebugEnabled()) {
240                 log.debug("the context: "+contextNameNode.getNodeValue() +" is possible context for node #"+nodeNumber+" by user: " +user);
241             }
242         }
243         synchronized(cache) {
244             cache.contextAdd(currentContext, list);
245         }
246         return list;
247     }
248
249     public boolean check(UserContext user, int nodeNumber, Operation operation) throws SecurityException JavaDoc{
250         if (log.isDebugEnabled()) {
251             log.debug("check on node #" + nodeNumber + " by user: " + user + " for operation " + operation);
252         }
253
254         // is our usercontext still valid?
255
if(!manager.getAuthentication().isValid(user)) {
256             String JavaDoc msg = "the usercontext was expired";
257             log.error(msg);
258             throw new java.lang.SecurityException JavaDoc(msg);
259         }
260         // operations can be granted for the whole system...
261
if(globalAllowedOperations.contains(operation)) {
262             log.debug("not retrieving the node, since operation:" + operation + " is granted to everyone");
263             return true;
264         }
265
266         // look which groups belong to this,...
267
MMObjectNode node = getMMNode(nodeNumber);
268         String JavaDoc context = node.getStringValue("owner");
269
270         return check(user, context, operation.toString());
271     }
272
273     private boolean check(UserContext user, int nodeNumber, String JavaDoc operation) throws SecurityException JavaDoc {
274         return check(user, getContext(user, nodeNumber), operation);
275     }
276
277     private boolean check(UserContext user, String JavaDoc context, Operation operation) throws SecurityException JavaDoc {
278         return check(user, context, operation.toString());
279     }
280
281     private boolean check(UserContext user, String JavaDoc context, String JavaDoc operation) throws SecurityException JavaDoc {
282         // look if we have this one already inside the positive cache...
283
synchronized(cache) {
284             Boolean JavaDoc result = cache.rightGet(operation, context, user.getIdentifier());
285             if(result != null) {
286                 log.trace("cache hit");
287                 return result.booleanValue();
288             }
289         }
290
291         String JavaDoc xpath;
292         xpath = "/contextconfig/contexts/context[@name='"+context+"']";
293         Node found;
294         try {
295             if (log.isDebugEnabled()) {
296                 log.trace("going to execute the query:" + xpath );
297             }
298             found = XPathAPI.selectSingleNode(document, xpath);
299
300             if (found == null) { // fall back to default
301
log.warn("context with name :'" + context + "' was not found in the configuration " + configResource );
302
303                 // retrieve the default context...
304
xpath = "/contextconfig/contexts/context[@name = ancestor::contexts/@default]";
305
306                 if (log.isDebugEnabled()) {
307                     log.trace("going to execute the query:" + xpath + " on file : " + configResource);
308                 }
309
310                 found = XPathAPI.selectSingleNode(document, xpath);
311
312                 if (found == null) {
313                     throw new SecurityException JavaDoc("Configuration error: Context " + context + " not found and no default context found either (change " + configResource + ")");
314                 }
315
316                 // put it in the cache
317
NamedNodeMap nnm = found.getAttributes();
318                 Node defaultContextNode = nnm.getNamedItem("name");
319                 String JavaDoc defaultContext = defaultContextNode.getNodeValue();
320
321                 synchronized(replaceNotFound) {
322                         replaceNotFound.put(context, defaultContext);
323                 }
324             }
325
326             // found is not null now.
327
// now get the requested operation
328

329             // now do the same query with the default context...
330
xpath = "operation[@type='" + operation + "']/grant";
331             if (log.isDebugEnabled()) {
332                 log.debug("going to execute the query:" + xpath + " On " + found.toString());
333             }
334             NodeList grants = XPathAPI.selectNodeList(found, xpath);
335
336             if (log.isDebugEnabled()) {
337                 log.debug("Found " + grants.getLength() + " grants on " + operation + " for context " + context) ;
338             }
339
340             Set allowedGroups = new HashSet();
341             for(int currentNode = 0; currentNode < grants.getLength(); currentNode++) {
342                 Node contains = grants.item(currentNode);
343                 NamedNodeMap nnm = contains.getAttributes();
344                 Node groupNameNode = nnm.getNamedItem("group");
345                 if (groupNameNode == null) {
346                     throw new SecurityException JavaDoc("Configuration error: 'grant' element must contain attribute 'group'");
347                 }
348                 allowedGroups.add(groupNameNode.getNodeValue());
349                 if (log.isDebugEnabled()) {
350                     log.debug("the group "+groupNameNode.getNodeValue() +" is granted for context " + context);
351                 }
352             }
353
354             boolean allowed = userInGroups(user.getIdentifier(), allowedGroups, new HashSet());
355             if (log.isDebugEnabled()) {
356                 if (allowed) {
357                     log.debug("operation " + operation + " was permitted for user with id " + user);
358                 } else {
359                     log.debug("operation " + operation + " was NOT permitted for user with id " + user);
360                 }
361             }
362
363             // put it in the cache
364
synchronized(cache) {
365                 cache.rightAdd(operation, context, user.getIdentifier(), allowed);
366             }
367
368             return allowed;
369
370         } catch(javax.xml.transform.TransformerException JavaDoc te) {
371             log.error("Error executing query.");
372             log.error( Logging.stackTrace(te));
373             throw new java.lang.SecurityException JavaDoc("error executing query: '"+xpath+"' ");
374         }
375
376     }
377
378
379
380     private boolean userInGroups(String JavaDoc user, Set groups, Set done) {
381         // look if we have something to do...
382
if(groups.size() == 0) {
383             log.debug("entering userInGroups(recursive) with username: '"+user+"' without any groups, so user was not found..");
384             return false;
385         }
386         log.debug("entering userInGroups(recursive) with username: '"+user+"' and look if the user is in the following groups:");
387
388         if (log.isDebugEnabled()) {
389             Iterator di = groups.iterator();
390             while (di.hasNext()) {
391                 log.debug("\t -> group : " + di.next());
392             }
393         }
394
395         Iterator i = groups.iterator();
396         Set fetchedGroups = new HashSet();
397         while(i.hasNext()) {
398             // get the group we are researching....
399
String JavaDoc groupname = (String JavaDoc)i.next();
400             // well, since we are already exploring ourselve, no need to do it again....
401
done.add(groupname);
402             log.debug("\tresearching group with name : "+groupname);
403
404             // do the xpath query...
405
String JavaDoc xpath = "/contextconfig/groups/group[@name='"+groupname+"']/contains";
406             log.debug("\tgoing to execute the query:" + xpath );
407             NodeIterator found;
408             try {
409                 found = XPathAPI.selectNodeIterator(document, xpath);
410             } catch(javax.xml.transform.TransformerException JavaDoc te) {
411                 log.error("error executing query: '"+xpath+"' ");
412                 log.error( Logging.stackTrace(te));
413                 throw new java.lang.SecurityException JavaDoc("error executing query: '"+xpath+"' ");
414             }
415             // research the result...
416
for(Node contains = found.nextNode(); contains != null; contains = found.nextNode()) {
417                 NamedNodeMap nnm = contains.getAttributes();
418                 String JavaDoc type = nnm.getNamedItem("type").getNodeValue();
419                 String JavaDoc named = nnm.getNamedItem("named").getNodeValue();
420                 log.debug("\t<contains type=\""+type+"\" named=\""+named+"\" />");
421                 if(type.equals("group")) {
422                     // this is a group...
423
// when not already known, add it to our to fetch-list
424
if(!done.contains(named)) {
425                         log.debug("\tfound a new group with name "+named+", which could contain our user, adding it to the to fetch list");
426                         fetchedGroups.add(named);
427                     }
428                 } else if(type.equals("user")) {
429                     // oh, maybe its me !!
430
if(named.equals(user)){
431                         log.debug("found the user with name " + named + " thus allowed." );
432                         return true;
433                     }
434                     log.debug("\tdid found the user with name " + named + " but is not we are looking for.");
435                 } else {
436                     String JavaDoc msg = "dont know the type:" + type;
437                     log.error(msg);
438                     throw new SecurityException JavaDoc(msg);
439                 }
440             }
441         }
442         return userInGroups(user, fetchedGroups, done);
443     }
444
445     public void verify(UserContext user, int nodeNumber, Operation operation) throws SecurityException JavaDoc {
446         if (log.isDebugEnabled()) {
447             if (operation.getInt() > Operation.READ_INT ) {
448                 log.debug("assert on node #" + nodeNumber + " by user: " + user + " for operation " + operation);
449             } else {
450                 log.trace("assert on node #" + nodeNumber +" by user: " + user + " for operation " + operation);
451             }
452         }
453         if (!check(user, nodeNumber, operation) ) {
454             throw new SecurityException JavaDoc("Operation '" + operation + "' on " + nodeNumber + " was NOT permitted to " + user.getIdentifier());
455         }
456     }
457
458
459     public boolean check(UserContext user, int nodeNumber, int srcNodeNumber, int dstNodeNumber, Operation operation) throws SecurityException JavaDoc {
460         if (operation == Operation.CREATE) {
461             // may link on both nodes
462
return check(user, srcNodeNumber, "link") && check(user, dstNodeNumber, "link");
463         } else if (operation == Operation.CHANGE_RELATION) {
464             return check(user, nodeNumber, Operation.WRITE.toString()) &&
465                 check(user, srcNodeNumber, "link") && check(user, dstNodeNumber, "link");
466         } else {
467             throw new RuntimeException JavaDoc("Called check with wrong operation " + operation);
468         }
469     }
470
471     public void verify(UserContext user, int nodeNumber, int srcNodeNumber, int dstNodeNumber, Operation operation) throws SecurityException JavaDoc {
472         if (operation == Operation.CREATE) {
473             // may link on both nodes
474
if(!check(user, srcNodeNumber, "link")) {
475                 String JavaDoc msg = "Operation 'link' on " + srcNodeNumber + " was NOT permitted to " + user.getIdentifier();
476                 log.error(msg);
477                 throw new SecurityException JavaDoc(msg);
478             }
479             if (! check(user, dstNodeNumber, "link")) {
480                 String JavaDoc msg = "Operation 'link' on " + dstNodeNumber + " was NOT permitted to " + user.getIdentifier();
481                 log.error(msg);
482                 throw new SecurityException JavaDoc(msg);
483             }
484         } else if (operation == Operation.CHANGE_RELATION) {
485             if(!check(user, srcNodeNumber, "link")) {
486                 String JavaDoc msg = "Operation 'link' on " + srcNodeNumber + " was NOT permitted to " + user.getIdentifier();
487                 log.error(msg);
488                 throw new SecurityException JavaDoc(msg);
489             }
490             if (! check(user, dstNodeNumber, "link")) {
491                 String JavaDoc msg = "Operation 'link' on " + dstNodeNumber + " was NOT permitted to " + user.getIdentifier();
492                 log.error(msg);
493                 throw new SecurityException JavaDoc(msg);
494             }
495             verify(user, nodeNumber, Operation.WRITE);
496         } else {
497             throw new RuntimeException JavaDoc("Called check with wrong operation " + operation);
498         }
499     }
500
501     private void getGlobalAllowedOperations() {
502         // get all the Operations and add them to the globalAllowedOperations set..
503
String JavaDoc xpath = "/contextconfig/global/allowed";
504         log.debug("going to execute the query:" + xpath );
505         NodeIterator found;
506         try {
507             found = XPathAPI.selectNodeIterator(document, xpath);
508         } catch(javax.xml.transform.TransformerException JavaDoc te) {
509             log.error("error executing query: '"+xpath+"' ");
510             log.error( Logging.stackTrace(te));
511             throw new java.lang.SecurityException JavaDoc("error executing query: '"+xpath+"' ");
512         }
513         Node allowed;
514         for(allowed = found.nextNode(); allowed != null; allowed = found.nextNode()) {
515             NamedNodeMap nnm = allowed.getAttributes();
516             Node contextNameNode = nnm.getNamedItem("operation");
517             Operation operation = Operation.getOperation(contextNameNode.getNodeValue());
518             log.info("Everyone may do operation:" + operation);
519             if(globalAllowedOperations.contains(operation)) throw new java.lang.SecurityException JavaDoc("operation:" + operation + " already in allowed list");
520             globalAllowedOperations.add(operation);
521         }
522     }
523
524     private static org.mmbase.module.core.MMObjectBuilder builder = null;
525
526     private MMObjectNode getMMNode(int n) {
527         if(builder == null) {
528             org.mmbase.module.core.MMBase mmb = (org.mmbase.module.core.MMBase)org.mmbase.module.Module.getModule("mmbaseroot");
529             builder = mmb.getMMObject("typedef");
530             if(builder == null) {
531                 String JavaDoc msg = "builder 'typedef' not found";
532                 log.error(msg);
533                 //throw new NotFoundException(msg);
534
throw new SecurityException JavaDoc(msg);
535             }
536         }
537         MMObjectNode node = builder.getNode(n);
538         if(node == null) {
539             String JavaDoc msg = "node " + n + " not found";
540             log.error(msg);
541             //throw new NotFoundException(msg);
542
throw new SecurityException JavaDoc(msg);
543         }
544         return node;
545     }
546
547
548     protected SortedSet getAllContexts() {
549         return allContexts;
550     }
551
552     protected SortedSet getDisallowingContexts(UserContext user, Operation operation) {
553         if (operation != Operation.READ) throw new UnsupportedOperationException JavaDoc("Currently only implemented for READ");
554         SortedSet set = new TreeSet();
555         Iterator i = getAllContexts().iterator();
556         while (i.hasNext()) {
557             String JavaDoc context = (String JavaDoc) i.next();
558             if (! check(user, context, operation)) {
559                 set.add(context);
560             }
561         }
562         return set;
563     }
564     
565
566     public QueryCheck check(UserContext userContext, Query query, Operation operation) {
567         if(globalAllowedOperations.contains(operation)) {
568             return COMPLETE_CHECK;
569         } else {
570             if (operation == Operation.READ) {
571
572                 AllowingContexts ac = (AllowingContexts) allowingContextsCache.get(userContext.getIdentifier());
573                 if (ac == null) {
574                     // smart stuff for query-modification
575
SortedSet disallowing = getDisallowingContexts(userContext, operation);
576                     SortedSet contexts;
577                     boolean inverse;
578                     if (log.isDebugEnabled()) {
579                         log.debug("disallowing: " + disallowing + " all " + getAllContexts());
580                     }
581
582                     // searching which is 'smallest' disallowing contexts, or allowing contexts.
583
if (disallowing.size() < (getAllContexts().size() / 2)) {
584                         contexts = disallowing;
585                         inverse = true;
586                     } else {
587                         contexts = new TreeSet(getAllContexts());
588                         contexts.removeAll(disallowing);
589                         inverse = false;
590                     }
591                     ac = new AllowingContexts(contexts, inverse);
592                     allowingContextsCache.put(userContext.getIdentifier(), ac);
593                 }
594                 
595                 if (ac.contexts.size() == 0) {
596                     if (ac.inverse) {
597                         return COMPLETE_CHECK;
598                     } else {
599                         // may read nothing
600
Constraint mayNothing = query.createConstraint(query.createStepField((Step) query.getSteps().get(0), "number"), new Integer JavaDoc(-1));
601                         return new Authorization.QueryCheck(true, mayNothing);
602                     }
603                 }
604
605                 List steps = query.getSteps();
606                 if (steps.size() * ac.contexts.size() < maxContextsInQuery) {
607                     Iterator i = steps.iterator();
608                     Constraint constraint = null;
609                     while (i.hasNext()) {
610                         Step step = (Step) i.next();
611                         StepField field = query.createStepField(step, "owner");
612                         Constraint newConstraint = query.createConstraint(field, ac.contexts);
613                         if (ac.inverse) query.setInverse(newConstraint, true);
614                         if (constraint == null) {
615                             constraint = newConstraint;
616                         } else {
617                             constraint = query.createConstraint(constraint, CompositeConstraint.LOGICAL_AND, newConstraint);
618                         }
619                     }
620                     return new Authorization.QueryCheck(true, constraint);
621                 } else { // query would grow too large
622
return Authorization.NO_CHECK;
623                 }
624
625             } else {
626                 //not checking for READ: never mind, this is only used for read checks any way
627
return Authorization.NO_CHECK;
628             }
629         }
630     }
631
632     private static class AllowingContexts {
633         SortedSet contexts;
634         boolean inverse;
635         AllowingContexts(SortedSet c, boolean i) {
636             contexts = c;
637             inverse = i;
638         }
639         
640     }
641 }
642
Popular Tags