001: /*
002:
003: This software is OSI Certified Open Source Software.
004: OSI Certified is a certification mark of the Open Source Initiative.
005:
006: The license (Mozilla version 1.0) can be read at the MMBase site.
007: See http://www.MMBase.org/license
008:
009: */
010: package org.mmbase.security.implementation.context;
011:
012: import org.mmbase.bridge.Query;
013: import org.mmbase.cache.Cache;
014: import org.mmbase.storage.search.*;
015: import java.util.*;
016:
017: import org.w3c.dom.*;
018: import org.xml.sax.InputSource;
019:
020: import javax.xml.xpath.*;
021:
022: import org.mmbase.module.core.MMBase;
023: import org.mmbase.module.core.MMObjectNode;
024: import org.mmbase.security.*;
025: import org.mmbase.security.SecurityException; // must be imported explicity, because it is also in
026: // java.lang
027: import org.mmbase.util.logging.Logger;
028: import org.mmbase.util.logging.Logging;
029:
030: /**
031: * Authorization based on a XML-configuration file. The XML file contains users, groups and
032: * contexts. Contextes provide rights to users and/or groups and are identified by a string (which
033: * is stored in the owner field).
034: *
035: * @author Eduard Witteveen
036: * @author Pierre van Rooden
037: * @author Michiel Meeuwissen
038: * @version $Id: ContextAuthorization.java,v 1.46 2007/06/06 11:35:47 nklasens Exp $
039: * @see ContextAuthentication
040: */
041: public class ContextAuthorization extends Authorization {
042: private static final Logger log = Logging
043: .getLoggerInstance(ContextAuthorization.class);
044: private Document document;
045: private ContextCache cache = new ContextCache();
046:
047: protected Cache<String, AllowingContexts> allowingContextsCache = new Cache<String, AllowingContexts>(
048: 200) { // 200 users.
049: public String getName() {
050: return "CS:AllowingContextsCache";
051: }
052:
053: public String getDescription() {
054: return "Links user id to a set of contexts";
055: }
056: };
057:
058: private int maxContextsInQuery = 50; // must be configurable
059:
060: /** contains elements of type = Operation */
061: private Set<Operation> globalAllowedOperations = new HashSet<Operation>();
062: private Map<String, String> replaceNotFound = new HashMap<String, String>();
063: private Map<UserContext, String> userDefaultContexts = new HashMap<UserContext, String>();
064: private SortedSet<String> allContexts;
065:
066: protected void load() {
067: log.debug("using: '" + configResource
068: + "' as config file for authentication");
069: try {
070: InputSource in = MMBaseCopConfig.securityLoader
071: .getInputSource(configResource);
072: // clear the cache of unfound contexts
073: replaceNotFound.clear();
074: allowingContextsCache.clear();
075: // clear the cache of user default contexts
076: userDefaultContexts.clear();
077: // reload the security xml document
078: document = org.mmbase.util.XMLBasicReader
079: .getDocumentBuilder(this .getClass()).parse(in);
080: getGlobalAllowedOperations();
081: setAllContexts();
082: } catch (org.xml.sax.SAXException se) {
083: String message = "error loading configfile :'"
084: + configResource + "'(" + se + "->"
085: + se.getMessage() + "(" + se.getMessage() + "))";
086: throw new SecurityException(message, se);
087: } catch (java.io.IOException ioe) {
088: throw new SecurityException("error loading configfile :'"
089: + configResource + "'(" + ioe + ")", ioe);
090: }
091: log.debug("loaded: '" + configResource
092: + "' as config file for authorization");
093: }
094:
095: public String getDefaultContext(UserContext user)
096: throws SecurityException {
097: String defaultContext = userDefaultContexts.get(user);
098: if (defaultContext == null) {
099: String xpath = "/contextconfig/accounts/user[@name='"
100: + user.getIdentifier() + "']";
101: Node found;
102: try {
103: log.debug("going to execute the query:" + xpath
104: + " on file : " + configResource);
105: XPath xp = XPathFactory.newInstance().newXPath();
106: found = (Node) xp.evaluate(xpath, document,
107: XPathConstants.NODE);
108: } catch (XPathExpressionException xe) {
109: throw new SecurityException(
110: "error executing query: '" + xpath
111: + "' on file: '" + configResource + "'",
112: xe);
113: }
114: if (found == null) {
115: throw new SecurityException("Could not find user "
116: + user.getIdentifier()
117: + " in context security config file ("
118: + configResource + ")");
119: }
120:
121: NamedNodeMap nnm = found.getAttributes();
122: Node contextNode = nnm.getNamedItem("context");
123: defaultContext = contextNode.getNodeValue();
124: userDefaultContexts.put(user, defaultContext);
125: }
126: if (log.isDebugEnabled()) {
127: log.debug("user with name: " + user
128: + " has the default context: " + defaultContext);
129: }
130: return defaultContext;
131: }
132:
133: public void create(UserContext user, int nodeNumber)
134: throws SecurityException {
135: if (log.isDebugEnabled()) {
136: log.debug("create on node #" + nodeNumber + " by user: "
137: + user);
138: }
139: String defaultContext = getDefaultContext(user);
140: setContext(user, nodeNumber, defaultContext);
141: }
142:
143: public void update(UserContext user, int nodeNumber)
144: throws SecurityException {
145: if (log.isDebugEnabled()) {
146: log.debug("update on node #" + nodeNumber + " by user: "
147: + user);
148: }
149: }
150:
151: public void remove(UserContext user, int nodeNumber)
152: throws SecurityException {
153: if (log.isDebugEnabled()) {
154: log.debug("remove on node #" + nodeNumber + " by user: "
155: + user);
156: }
157: }
158:
159: public void setContext(UserContext user, int nodeNumber,
160: String context) throws SecurityException {
161: // notify the log
162: if (log.isDebugEnabled()) {
163: log.debug("set context on node #" + nodeNumber
164: + " by user: " + user + " to " + context);
165: }
166: // don't even bother if the context was already set.
167: MMObjectNode node = getMMNode(nodeNumber);
168: if (node.getStringValue("owner").equals(context))
169: return;
170:
171: // check if is a valid context for us..
172: Set<String> possible = getPossibleContexts(user, nodeNumber);
173: if (!possible.contains(context)) {
174: throw new SecurityException("could not set the context to "
175: + context + " for node #" + nodeNumber
176: + " by user: " + user);
177: }
178:
179: // check if this operation is allowed? (should also be done somewhere else, but we can never be sure enough)
180: verify(user, nodeNumber, Operation.CHANGE_CONTEXT);
181:
182: // well now really set it...
183: node.setValue("owner", context);
184: node.commit();
185: if (log.isDebugEnabled()) {
186: log.debug("changed context settings of node #" + nodeNumber
187: + " to context: " + context + " by user: " + user);
188: }
189: }
190:
191: public String getContext(UserContext user, int nodeNumber)
192: throws SecurityException {
193: // notify the log
194: if (log.isDebugEnabled()) {
195: log.debug("get context on node #" + nodeNumber
196: + " by user: " + user);
197: }
198:
199: // check if this operation is allowed? (should also be done somewhere else, but we can never be sure enough)
200: verify(user, nodeNumber, Operation.READ);
201:
202: // and get the value...
203: return getContext(nodeNumber);
204: }
205:
206: private void setAllContexts() throws SecurityException {
207: allContexts = new TreeSet<String>();
208: String xpath = "/contextconfig/contexts/context";
209: log.trace("going to execute the query:" + xpath);
210: NodeList found;
211: try {
212: XPath xp = XPathFactory.newInstance().newXPath();
213: found = (NodeList) xp.evaluate(xpath, document,
214: XPathConstants.NODESET);
215: } catch (XPathExpressionException xe) {
216: throw new SecurityException("error executing query: '"
217: + xpath + "' ", xe);
218: }
219: for (int i = 0; i < found.getLength(); i++) {
220: Node context = found.item(i);
221: NamedNodeMap nnm = context.getAttributes();
222: Node contextNameNode = nnm.getNamedItem("name");
223: allContexts.add(contextNameNode.getNodeValue());
224: }
225: }
226:
227: public Set<String> getPossibleContexts(UserContext user,
228: int nodeNumber) throws SecurityException {
229: if (log.isDebugEnabled()) {
230: log.debug("get possible context on node #" + nodeNumber
231: + " by user: " + user);
232: }
233:
234: // check if this operation is allowed? (should also be done somewhere else, but we can never be sure enough)
235: // TODO: research if we maybe better could use WRITE or CHANGE_CONTEXT as rights for this operation...
236: verify(user, nodeNumber, Operation.READ);
237:
238: // retrieve the current context..
239: String currentContext = getContext(user, nodeNumber);
240: synchronized (replaceNotFound) {
241: if (replaceNotFound.containsKey(currentContext)) {
242: currentContext = replaceNotFound.get(currentContext);
243: }
244: }
245:
246: Set<String> list;
247: synchronized (cache) {
248: list = cache.contextGet(currentContext);
249: if (list != null) {
250: log.debug("cache hit");
251: return list;
252: }
253: list = new HashSet<String>();
254: }
255:
256: // possible contextes are dependeding of the context they're in...
257: String xpath = "/contextconfig/contexts/context[@name='"
258: + currentContext + "']/possible";
259: log.debug("going to execute the query:" + xpath);
260: NodeList found;
261: try {
262: XPath xp = XPathFactory.newInstance().newXPath();
263: found = (NodeList) xp.evaluate(xpath, document,
264: XPathConstants.NODESET);
265: } catch (XPathExpressionException xe) {
266: throw new SecurityException("error executing query: '"
267: + xpath + "' ", xe);
268: }
269:
270: for (int i = 0; i < found.getLength(); i++) {
271: Node context = found.item(i);
272: NamedNodeMap nnm = context.getAttributes();
273: Node contextNameNode = nnm.getNamedItem("context");
274: list.add(contextNameNode.getNodeValue());
275: if (log.isDebugEnabled()) {
276: log.debug("the context: "
277: + contextNameNode.getNodeValue()
278: + " is possible context for node #"
279: + nodeNumber + " by user: " + user);
280: }
281: }
282: synchronized (cache) {
283: cache.contextAdd(currentContext, list);
284: }
285: return list;
286: }
287:
288: /**
289: * @since MMBase-1.9
290: */
291: protected String getContext(int nodeNumber) {
292: MMObjectNode node = getMMNode(nodeNumber);
293: return node.getStringValue("owner");
294: }
295:
296: public boolean check(UserContext user, int nodeNumber,
297: Operation operation) throws SecurityException {
298: if (log.isDebugEnabled()) {
299: log.debug("check on node #" + nodeNumber + " by user: "
300: + user + " for operation " + operation);
301: }
302:
303: // is our usercontext still valid?
304: if (!manager.getAuthentication().isValid(user)) {
305: String msg = "the usercontext was expired";
306: throw new java.lang.SecurityException(msg);
307: }
308: // operations can be granted for the whole system...
309: if (globalAllowedOperations.contains(operation)) {
310: log.debug("not retrieving the node, since operation:"
311: + operation + " is granted to everyone");
312: return true;
313: }
314:
315: // look which groups belong to this,...
316: String context = getContext(nodeNumber);
317: return check(user, context, operation.toString());
318: }
319:
320: private boolean check(UserContext user, int nodeNumber,
321: String operation) throws SecurityException {
322: return check(user, getContext(user, nodeNumber), operation);
323: }
324:
325: private boolean check(UserContext user, String context,
326: Operation operation) throws SecurityException {
327: return check(user, context, operation.toString());
328: }
329:
330: private boolean check(UserContext user, String context,
331: String operation) throws SecurityException {
332: // look if we have this one already inside the positive cache...
333: synchronized (cache) {
334: Boolean result = cache.rightGet(operation, context, user
335: .getIdentifier());
336: if (result != null) {
337: log.trace("cache hit");
338: return result.booleanValue();
339: }
340: }
341:
342: String xpath;
343: xpath = "/contextconfig/contexts/context[@name='" + context
344: + "']";
345: Node found;
346: try {
347: if (log.isDebugEnabled()) {
348: log.trace("going to execute the query:" + xpath);
349: }
350: XPathFactory xf = XPathFactory.newInstance();
351: found = (Node) xf.newXPath().evaluate(xpath, document,
352: XPathConstants.NODE);
353:
354: if (found == null) { // fall back to default
355: log.warn("context with name :'" + context
356: + "' was not found in the configuration "
357: + configResource);
358:
359: // retrieve the default context...
360: xpath = "/contextconfig/contexts/context[@name = ancestor::contexts/@default]";
361:
362: if (log.isDebugEnabled()) {
363: log.trace("going to execute the query:" + xpath
364: + " on file : " + configResource);
365: }
366:
367: found = (Node) xf.newXPath().evaluate(xpath, document,
368: XPathConstants.NODE);
369:
370: if (found == null) {
371: throw new SecurityException(
372: "Configuration error: Context "
373: + context
374: + " not found and no default context found either (change "
375: + configResource + ")");
376: }
377:
378: // put it in the cache
379: NamedNodeMap nnm = found.getAttributes();
380: Node defaultContextNode = nnm.getNamedItem("name");
381: String defaultContext = defaultContextNode
382: .getNodeValue();
383:
384: synchronized (replaceNotFound) {
385: replaceNotFound.put(context, defaultContext);
386: }
387: }
388:
389: // found is not null now.
390: // now get the requested operation
391:
392: // now do the same query with the default context...
393: xpath = "operation[@type='" + operation + "']/grant";
394: if (log.isDebugEnabled()) {
395: log.debug("going to execute the query:" + xpath
396: + " On " + found.toString());
397: }
398: NodeList grants = (NodeList) xf.newXPath().evaluate(xpath,
399: found, XPathConstants.NODESET);
400:
401: if (log.isDebugEnabled()) {
402: log.debug("Found " + grants.getLength() + " grants on "
403: + operation + " for context " + context);
404: }
405:
406: Set<String> allowedGroups = new HashSet<String>();
407: for (int currentNode = 0; currentNode < grants.getLength(); currentNode++) {
408: Node contains = grants.item(currentNode);
409: NamedNodeMap nnm = contains.getAttributes();
410: Node groupNameNode = nnm.getNamedItem("group");
411: if (groupNameNode == null) {
412: throw new SecurityException(
413: "Configuration error: 'grant' element must contain attribute 'group'");
414: }
415: allowedGroups.add(groupNameNode.getNodeValue());
416: if (log.isDebugEnabled()) {
417: log.debug("the group "
418: + groupNameNode.getNodeValue()
419: + " is granted for context " + context);
420: }
421: }
422:
423: boolean allowed = userInGroups(user.getIdentifier(),
424: allowedGroups, new HashSet<String>());
425: if (log.isDebugEnabled()) {
426: if (allowed) {
427: log
428: .debug("operation "
429: + operation
430: + " was permitted for user with id "
431: + user);
432: } else {
433: log.debug("operation " + operation
434: + " was NOT permitted for user with id "
435: + user);
436: }
437: }
438:
439: // put it in the cache
440: synchronized (cache) {
441: cache.rightAdd(operation, context,
442: user.getIdentifier(), allowed);
443: }
444:
445: return allowed;
446:
447: } catch (XPathExpressionException xe) {
448: throw new java.lang.SecurityException(
449: "error executing query: '" + xpath + "' ", xe);
450: }
451:
452: }
453:
454: private boolean userInGroups(String user, Set<String> groups,
455: Set<String> done) {
456: // look if we have something to do...
457: if (groups.size() == 0) {
458: log
459: .debug("entering userInGroups(recursive) with username: '"
460: + user
461: + "' without any groups, so user was not found..");
462: return false;
463: }
464:
465: if (log.isDebugEnabled()) {
466: log
467: .debug("entering userInGroups(recursive) with username: '"
468: + user
469: + "' and look if the user is in the following groups:");
470:
471: Iterator<String> di = groups.iterator();
472: while (di.hasNext()) {
473: log.debug("\t -> group : " + di.next());
474: }
475: }
476:
477: Set<String> fetchedGroups = new HashSet<String>();
478: for (String groupname : groups) {
479: // get the group we are researching....
480: // well, since we are already exploring ourselve, no need to do it again....
481: done.add(groupname);
482: // do the xpath query...
483: String xpath = "/contextconfig/groups/group[@name='"
484: + groupname + "']/contains";
485:
486: if (log.isDebugEnabled()) {
487: log.debug("\tresearching group with name : "
488: + groupname);
489: log.debug("\tgoing to execute the query:" + xpath);
490: }
491:
492: NodeList found;
493: XPathFactory xf = XPathFactory.newInstance();
494: try {
495: found = (NodeList) xf.newXPath().evaluate(xpath,
496: document, XPathConstants.NODESET);
497: } catch (XPathExpressionException xe) {
498: throw new java.lang.SecurityException(
499: "error executing query: '" + xpath + "' ", xe);
500: }
501: // research the result...
502: for (int i = 0; i < found.getLength(); i++) {
503: Node contains = found.item(i);
504: NamedNodeMap nnm = contains.getAttributes();
505: String type = nnm.getNamedItem("type").getNodeValue();
506: String named = nnm.getNamedItem("named").getNodeValue();
507: if (log.isDebugEnabled()) {
508: log.debug("\t<contains type=\"" + type
509: + "\" named=\"" + named + "\" />");
510: }
511: if (type.equals("group")) {
512: // this is a group...
513: // when not already known, add it to our to fetch-list
514: if (!done.contains(named)) {
515: log
516: .debug("\tfound a new group with name "
517: + named
518: + ", which could contain our user, adding it to the to fetch list");
519: fetchedGroups.add(named);
520: }
521: } else if (type.equals("user")) {
522: // oh, maybe its me !!
523: if (named.equals(user)) {
524: log.debug("found the user with name " + named
525: + " thus allowed.");
526: return true;
527: }
528: log.debug("\tdid found the user with name " + named
529: + " but is not we are looking for.");
530: } else {
531: String msg = "dont know the type:" + type;
532: throw new SecurityException(msg);
533: }
534: }
535: }
536: return userInGroups(user, fetchedGroups, done);
537: }
538:
539: public void verify(UserContext user, int nodeNumber,
540: Operation operation) throws SecurityException {
541: if (log.isDebugEnabled()) {
542: if (operation.getInt() > Operation.READ_INT) {
543: log.debug("assert on node #" + nodeNumber
544: + " by user: " + user + " for operation "
545: + operation);
546: } else {
547: log.trace("assert on node #" + nodeNumber
548: + " by user: " + user + " for operation "
549: + operation);
550: }
551: }
552: if (!check(user, nodeNumber, operation)) {
553: throw new SecurityException("Operation '" + operation
554: + "' on " + nodeNumber + " ("
555: + getContext(nodeNumber)
556: + ") was NOT permitted to " + user.getIdentifier());
557: }
558: }
559:
560: public boolean check(UserContext user, int nodeNumber,
561: int srcNodeNumber, int dstNodeNumber, Operation operation)
562: throws SecurityException {
563: if (operation == Operation.CREATE) {
564: // may link on both nodes
565: return check(user, srcNodeNumber, "link")
566: && check(user, dstNodeNumber, "link");
567: } else if (operation == Operation.CHANGE_RELATION) {
568: return check(user, nodeNumber, Operation.WRITE.toString())
569: && check(user, srcNodeNumber, "link")
570: && check(user, dstNodeNumber, "link");
571: } else {
572: throw new RuntimeException(
573: "Called check with wrong operation " + operation);
574: }
575: }
576:
577: public void verify(UserContext user, int nodeNumber,
578: int srcNodeNumber, int dstNodeNumber, Operation operation)
579: throws SecurityException {
580: if (operation == Operation.CREATE) {
581: // may link on both nodes
582: if (!check(user, srcNodeNumber, "link")) {
583: String msg = "Operation 'link' on " + srcNodeNumber
584: + " was NOT permitted to "
585: + user.getIdentifier();
586: throw new SecurityException(msg);
587: }
588: if (!check(user, dstNodeNumber, "link")) {
589: String msg = "Operation 'link' on " + dstNodeNumber
590: + " was NOT permitted to "
591: + user.getIdentifier();
592: throw new SecurityException(msg);
593: }
594: } else if (operation == Operation.CHANGE_RELATION) {
595: if (!check(user, srcNodeNumber, "link")) {
596: String msg = "Operation 'link' on " + srcNodeNumber
597: + " was NOT permitted to "
598: + user.getIdentifier();
599: throw new SecurityException(msg);
600: }
601: if (!check(user, dstNodeNumber, "link")) {
602: String msg = "Operation 'link' on " + dstNodeNumber
603: + " was NOT permitted to "
604: + user.getIdentifier();
605: throw new SecurityException(msg);
606: }
607: verify(user, nodeNumber, Operation.WRITE);
608: } else {
609: throw new RuntimeException(
610: "Called check with wrong operation " + operation);
611: }
612: }
613:
614: private void getGlobalAllowedOperations() {
615: // get all the Operations and add them to the globalAllowedOperations set..
616: String xpath = "/contextconfig/global/allowed";
617: log.debug("going to execute the query:" + xpath);
618: NodeList found;
619: XPathFactory xf = XPathFactory.newInstance();
620: try {
621: found = (NodeList) xf.newXPath().evaluate(xpath, document,
622: XPathConstants.NODESET);
623: } catch (XPathExpressionException xe) {
624: throw new SecurityException("error executing query: '"
625: + xpath + "' ", xe);
626: }
627:
628: for (int i = 0; i < found.getLength(); i++) {
629: Node allowed = found.item(i);
630: NamedNodeMap nnm = allowed.getAttributes();
631: Node contextNameNode = nnm.getNamedItem("operation");
632: Operation operation = Operation
633: .getOperation(contextNameNode.getNodeValue());
634: log.info("Everyone may do operation:" + operation);
635: if (globalAllowedOperations.contains(operation))
636: throw new SecurityException("operation:" + operation
637: + " already in allowed list");
638: globalAllowedOperations.add(operation);
639: }
640: }
641:
642: private static org.mmbase.module.core.MMObjectBuilder builder = null;
643:
644: private MMObjectNode getMMNode(int n) {
645: if (builder == null) {
646: MMBase mmb = MMBase.getMMBase();
647: builder = mmb.getMMObject("typedef");
648: if (builder == null) {
649: String msg = "builder 'typedef' not found";
650: //throw new NotFoundException(msg);
651: throw new SecurityException(msg);
652: }
653: }
654: MMObjectNode node = builder.getNode(n);
655: if (node == null) {
656: String msg = "node " + n + " not found";
657: //throw new NotFoundException(msg);
658: throw new SecurityException(msg);
659: }
660: return node;
661: }
662:
663: protected SortedSet<String> getAllContexts() {
664: return allContexts;
665: }
666:
667: protected SortedSet<String> getDisallowingContexts(
668: UserContext user, Operation operation) {
669: if (operation != Operation.READ)
670: throw new UnsupportedOperationException(
671: "Currently only implemented for READ");
672: SortedSet<String> set = new TreeSet<String>();
673: for (String context : getAllContexts()) {
674: if (!check(user, context, operation)) {
675: set.add(context);
676: }
677: }
678: return set;
679: }
680:
681: public QueryCheck check(UserContext userContext, Query query,
682: Operation operation) {
683: if (globalAllowedOperations.contains(operation)) {
684: return COMPLETE_CHECK;
685: } else {
686: if (operation == Operation.READ) {
687:
688: AllowingContexts ac = allowingContextsCache
689: .get(userContext.getIdentifier());
690: if (ac == null) {
691: // smart stuff for query-modification
692: SortedSet<String> disallowing = getDisallowingContexts(
693: userContext, operation);
694: SortedSet<String> contexts;
695: boolean inverse;
696: if (log.isDebugEnabled()) {
697: log.debug("disallowing: " + disallowing
698: + " all " + getAllContexts());
699: }
700:
701: // searching which is 'smallest' disallowing contexts, or allowing contexts.
702: if (disallowing.size() < (getAllContexts().size() / 2)) {
703: contexts = disallowing;
704: inverse = true;
705: } else {
706: contexts = new TreeSet<String>(getAllContexts());
707: contexts.removeAll(disallowing);
708: inverse = false;
709: }
710: ac = new AllowingContexts(contexts, inverse);
711: allowingContextsCache.put(userContext
712: .getIdentifier(), ac);
713: }
714:
715: if (ac.contexts.size() == 0) {
716: if (ac.inverse) {
717: return COMPLETE_CHECK;
718: } else {
719: // may read nothing
720: Constraint mayNothing = query.createConstraint(
721: query.createStepField(query.getSteps()
722: .get(0), "number"), -1);
723: return new Authorization.QueryCheck(true,
724: mayNothing);
725: }
726: }
727:
728: List<Step> steps = query.getSteps();
729: if (steps.size() * ac.contexts.size() < maxContextsInQuery) {
730: Iterator<Step> i = steps.iterator();
731: Constraint constraint = null;
732: while (i.hasNext()) {
733: Step step = i.next();
734: StepField field = query.createStepField(step,
735: "owner");
736: Constraint newConstraint = query
737: .createConstraint(field, ac.contexts);
738: if (ac.inverse)
739: query.setInverse(newConstraint, true);
740: if (constraint == null) {
741: constraint = newConstraint;
742: } else {
743: constraint = query.createConstraint(
744: constraint,
745: CompositeConstraint.LOGICAL_AND,
746: newConstraint);
747: }
748: }
749: return new Authorization.QueryCheck(true,
750: constraint);
751: } else { // query would grow too large
752: return Authorization.NO_CHECK;
753: }
754:
755: } else {
756: //not checking for READ: never mind, this is only used for read checks any way
757: return Authorization.NO_CHECK;
758: }
759: }
760: }
761:
762: private static class AllowingContexts {
763: private final SortedSet<String> contexts;
764: private final boolean inverse;
765:
766: AllowingContexts(SortedSet<String> c, boolean i) {
767: contexts = c;
768: inverse = i;
769: }
770: }
771: }
|