1 10 package org.mmbase.security.implementation.cloudcontext.builders; 11 12 import org.mmbase.security.implementation.cloudcontext.*; 13 import org.mmbase.security.SecurityException; 14 import org.mmbase.security.Authorization; 15 import org.mmbase.bridge.Query; 16 17 import java.util.*; 18 19 import org.mmbase.storage.search.*; 20 import org.mmbase.storage.search.implementation.*; 21 import org.mmbase.module.core.*; 22 import org.mmbase.module.corebuilders.InsRel; 23 import org.mmbase.cache.Cache; 24 import org.mmbase.security.*; 25 import org.mmbase.util.logging.Logger; 26 import org.mmbase.util.logging.Logging; 27 import org.mmbase.util.functions.*; 28 import org.mmbase.cache.AggregatedResultCache; 29 30 42 public class Contexts extends MMObjectBuilder { 43 private static final Logger log = Logging.getLoggerInstance(Contexts.class); 44 45 49 static final String DEFAULT_CONTEXT = "default"; static final int DEFAULT_MAX_CONTEXTS_IN_QUERY = 50; 51 public final static Parameter PARAMETER_OPERATION = new Parameter("operation", String .class); 52 public final static Parameter PARAMETER_GROUPORUSER = new Parameter("grouporuser", String .class); 53 54 public final static Parameter[] ALLOWS_PARAMETERS = { 55 PARAMETER_GROUPORUSER, 56 PARAMETER_OPERATION 57 }; 58 59 public final static Parameter[] PARENTSALLOW_PARAMETERS = ALLOWS_PARAMETERS; 60 61 62 public final static Parameter[] GRANT_PARAMETERS = { 63 PARAMETER_GROUPORUSER, 64 PARAMETER_OPERATION, 65 Parameter.USER 66 }; 67 68 public final static Parameter[] REVOKE_PARAMETERS = GRANT_PARAMETERS; 69 public final static Parameter[] MAYGRANT_PARAMETERS = GRANT_PARAMETERS; 70 public final static Parameter[] MAYREVOKE_PARAMETERS = REVOKE_PARAMETERS; 71 72 73 public final static Parameter[] MAY_PARAMETERS = { 74 Parameter.USER, 75 new Parameter("usertocheck", String .class), 76 PARAMETER_OPERATION 77 78 }; 79 80 81 protected static Cache contextCache = new Cache(30) { public String getName() { return "CCS:ContextCache"; } 83 public String getDescription() { return "Links owner field to Contexts MMObjectNodes"; } 84 }; 85 86 87 protected static Cache allowingContextsCache = new Cache(200) { public String getName() { return "CCS:AllowingContextsCache"; } 89 public String getDescription() { return "Links user id to a set of contexts"; } 90 }; 91 protected static class OperationsCache extends Cache { 92 OperationsCache() { 93 super(100); 94 } 95 public String getName() { return "CCS:SecurityOperations"; } 96 public String getDescription() { return "The groups associated with a security operation";} 97 98 public Object put(MMObjectNode context, Operation op, Set groups) { 99 return super.put(op.toString() + context.getNumber(), groups); 100 } 101 public Set get(MMObjectNode context, Operation op) { 102 return (Set) super.get(op.toString() + context.getNumber()); 103 } 104 105 }; 106 107 protected static OperationsCache operationsCache = new OperationsCache(); 108 109 110 111 114 115 protected static Map invalidableObjects = new HashMap(); 116 117 private boolean readAll = false; 118 private boolean allContextsPossible = true; 120 121 private int maxContextsInQuery = DEFAULT_MAX_CONTEXTS_IN_QUERY; 122 123 124 127 public boolean init() { 128 String s = (String ) getInitParameters().get("readall"); 129 readAll = "true".equals(s); 130 131 s = (String ) getInitParameters().get("allcontextspossible"); 132 allContextsPossible = ! "false".equals(s); 133 134 s = (String ) getInitParameters().get("maxcontextsinquery"); 135 if (! "".equals(s) && s != null) { 136 maxContextsInQuery = Integer.parseInt(s); 137 } 138 139 contextCache.putCache(); 140 allowingContextsCache.putCache(); 141 operationsCache.putCache(); 142 143 CacheInvalidator.getInstance().addCache(operationsCache); 144 CacheInvalidator.getInstance().addCache(contextCache); 145 CacheInvalidator.getInstance().addCache(allowingContextsCache); 146 CacheInvalidator.getInstance().addCache(invalidableObjects); 147 mmb.addLocalObserver(getTableName(), CacheInvalidator.getInstance()); 148 mmb.addRemoteObserver(getTableName(), CacheInvalidator.getInstance()); 149 150 return super.init(); 151 } 152 153 156 public static Contexts getBuilder() { 157 return (Contexts) MMBase.getMMBase().getBuilder("mmbasecontexts"); 158 } 159 160 161 165 166 public boolean mayDo(User user, int nodeId, int sourceNodeId, int destinationNodeId, Operation operation) throws SecurityException { 167 if (user.getRank().getInt() >= Rank.ADMIN_INT) { 169 return true; 170 } 171 172 174 return mayDo(user, nodeId, operation); 175 176 } 177 178 179 183 public boolean mayDo(User user, int nodeId, Operation operation) throws SecurityException { 184 185 MMObjectNode node = getNode(nodeId); 187 188 MMObjectBuilder builder = null; 189 if (node != null) { builder = node.getBuilder(); 191 } 192 193 if (operation == Operation.DELETE) { 194 if (user.getNode() != null && user.getNode().getNumber() == nodeId && operation == Operation.DELETE) return false; if (builder instanceof Contexts) { 196 try { 197 Users users = Users.getBuilder(); 198 BasicSearchQuery query = new BasicSearchQuery(true); 199 Step step = query.addStep(users); 200 BasicFieldValueConstraint constraint = new BasicFieldValueConstraint(new BasicStepField(step, users.getField("defaultcontext")), new Integer (nodeId)); 201 query.setConstraint(constraint); 202 BasicAggregatedField baf = query.addAggregatedField((Step) query.getSteps().get(0), users.getField("defaultcontext"), AggregatedField.AGGREGATION_TYPE_COUNT); 203 baf.setAlias("count"); 204 205 AggregatedResultCache cache = AggregatedResultCache.getCache(); 206 List resultList = (List) cache.get(query); 207 if (resultList == null) { 208 ResultBuilder resultBuilder = new ResultBuilder(mmb, query); 209 resultList = mmb.getSearchQueryHandler().getNodes(query, resultBuilder); 210 cache.put(query, resultList); 211 } 212 213 ResultNode result = (ResultNode) resultList.get(0); 214 int count = result.getIntValue("count"); 215 if (count > 0) return false; 216 217 220 } catch (SearchQueryException sqe) { 221 } 223 } 224 225 } 226 227 if (user.getRank().getInt() >= Rank.ADMIN_INT) { 229 return true; 230 } 231 232 233 if (node == null) { 234 log.warn("node #" + nodeId + " not found"); 235 return false; 236 } 237 238 if (readAll && operation == Operation.READ) { 239 return true; 240 } 241 242 243 244 if (builder instanceof InsRel) { 246 MMObjectNode source = getNode(node.getIntValue("snumber")); 247 MMObjectNode destination = getNode(node.getIntValue("dnumber")); 248 249 if (source.getBuilder() instanceof Users && destination.getBuilder() instanceof Ranks) { 250 251 if (operation == Operation.WRITE || operation == Operation.CHANGE_RELATION) { 253 return false; 254 } 255 if (operation == Operation.DELETE || operation == Operation.CREATE) { 256 257 if(user.getRank().getInt() <= Rank.BASICUSER.getInt()) return false; 259 260 if (user.getNode() != null && user.getNode().equals(source)) { 262 log.debug("May not unlink rank with own user object"); 263 return false; 264 } 265 266 if (user.getRank().getInt() <= destination.getIntValue("rank")) { 268 return false; 269 } 270 } 271 return true; 273 } 274 if (builder instanceof RightsRel) { 275 if (operation == Operation.WRITE || operation == Operation.CHANGE_RELATION) { 277 return false; 278 } 279 if (operation == Operation.CREATE) { 280 return mayGrant(source, destination, Operation.getOperation(node.getStringValue("operation")), user.getNode()); 281 } 282 if (operation == Operation.DELETE) { 283 return mayRevoke(source, destination, Operation.getOperation(node.getStringValue("operation")), user.getNode()); 284 } 285 } 286 if (source.getBuilder() instanceof Groups && destination.getBuilder() instanceof Users && operation != Operation.READ) { 287 if (getNode(node.getIntValue("rnumber")).getStringValue("sname").equals("contains")) { 288 Rank destRank = ((Users) destination.getBuilder()).getRank(destination); 290 if (user.getRank().getInt() <= destRank.getInt()) { 291 return false; 292 } 293 } 294 } 295 } 296 297 298 310 311 if (isOwnNode(user, node)) { 313 if ((operation == Operation.READ || operation == Operation.WRITE)) { 314 if (log.isDebugEnabled()) { 315 log.debug("May always " + operation + " on own user node: " + nodeId); 316 } 317 return true; 318 } 319 if (operation == Operation.DELETE || operation == Operation.CHANGE_CONTEXT) { 320 return false; 322 } 323 } 324 325 326 MMObjectNode contextNode = getContextNode(node); if (contextNode == null) { 328 log.warn("Did not find context node for " + node); 329 return false; 330 } 331 return mayDo(user, contextNode, operation); 332 } 333 334 338 protected boolean isOwnNode(User user, MMObjectNode node) { 339 MMObjectNode userNode = user.getNode(); 340 return (userNode != null && userNode.getBuilder() instanceof Users && userNode.equals(node)); 341 } 342 343 346 347 protected boolean mayDo(User user, MMObjectNode contextNode, Operation operation) { 348 return mayDo(user.getNode(), contextNode, operation, true); 349 } 350 351 protected boolean mayDo(MMObjectNode user, MMObjectNode contextNode, Operation operation, boolean checkOwnRights) { 352 353 Set groupsAndUsers = getGroupsAndUsers(contextNode, operation); 354 355 if (checkOwnRights) { 356 if (groupsAndUsers.contains(user)) return true; 357 } 358 359 Iterator iter = groupsAndUsers.iterator(); 360 while (iter.hasNext()) { 362 MMObjectNode group = (MMObjectNode) iter.next(); 363 if (! (group.getBuilder() instanceof Groups)) continue; 364 if (log.isDebugEnabled()) log.trace("checking group " + group); 365 if(Groups.getBuilder().contains(group, user)) { 366 if (log.isDebugEnabled()) { 367 log.debug("User " + user.getStringValue("username") + " may " + operation + " according to context " + contextNode); 368 } 369 return true; 370 } 371 } 372 if (log.isDebugEnabled()) { 373 log.debug("User " + user.getStringValue("username") + " may not " + operation + " according to context " + contextNode); 374 } 375 return false; 376 377 } 378 379 380 383 protected SortedSet getAllContexts() { 384 SortedSet all = (SortedSet) invalidableObjects.get("ALL"); 385 if (all == null) { 386 try { 387 Iterator i = getNodes(new NodeSearchQuery(this)).iterator(); all = new TreeSet(); 389 while (i.hasNext()) { 390 MMObjectNode context = (MMObjectNode) i.next(); 391 all.add(context.getStringValue("name")); 392 } 393 394 invalidableObjects.put("ALL", Collections.unmodifiableSortedSet(all)); 395 } catch (SearchQueryException sqe) { 396 log.error( Logging.stackTrace(sqe)); 397 } 398 } 399 return all; 400 } 401 402 405 protected SortedSet getDisallowingContexts(User user, Operation operation) { 406 if (operation != Operation.READ) throw new UnsupportedOperationException ("Currently only implemented for READ"); 407 SortedSet set = new TreeSet(); 408 if (!readAll) { 409 Iterator i = getAllContexts().iterator(); 410 while (i.hasNext()) { 411 String context = (String ) i.next(); 412 MMObjectNode contextNode = getContextNode(context); 413 if (! mayDo(user, contextNode, operation)) { 414 set.add(context); 415 } 416 } 417 } 418 419 return Collections.unmodifiableSortedSet(set); 420 } 421 422 protected SortedSet getAllowingContexts(User user, Operation operation) { 423 if (operation != Operation.READ) throw new UnsupportedOperationException ("Currently only implemented for READ"); 424 if (readAll) { return getAllContexts(); } 425 426 SortedSet set = new TreeSet(getAllContexts()); 427 set.removeAll(getDisallowingContexts(user, operation)); 428 429 return Collections.unmodifiableSortedSet(set); 430 431 } 432 433 434 438 439 public Authorization.QueryCheck check(User userContext, Query query, Operation operation) { 440 if (userContext.getRank().getInt() >= Rank.ADMIN_INT) { 441 return Authorization.COMPLETE_CHECK; 442 } else { 443 if (operation == Operation.READ && readAll) { 444 return Authorization.COMPLETE_CHECK; 445 } else if (operation == Operation.READ) { 446 447 AllowingContexts ac = (AllowingContexts) allowingContextsCache.get(userContext.getIdentifier()); 448 if (ac == null) { 449 SortedSet disallowing = getDisallowingContexts(userContext, operation); 451 SortedSet contexts; 452 boolean inverse; 453 if (log.isDebugEnabled()) { 454 log.debug("disallowing: " + disallowing + " all " + getAllContexts()); 455 } 456 457 if (disallowing.size() < (getAllContexts().size() / 2)) { 459 contexts = disallowing; 460 inverse = true; 461 } else { 462 contexts = new TreeSet(getAllContexts()); 463 contexts.removeAll(disallowing); 464 inverse = false; 465 } 466 ac = new AllowingContexts(contexts, inverse); 467 allowingContextsCache.put(userContext.getIdentifier(), ac); 468 } 469 470 List steps = query.getSteps(); 471 Constraint constraint = null; 472 473 { 475 Iterator i = steps.iterator(); 476 while (i.hasNext()) { 477 Step step = (Step) i.next(); 478 Constraint newConstraint = null; 479 if (step.getTableName().equals("mmbasegroups")) { 480 newConstraint = query.createConstraint(query.createStepField(step, "number"), userContext.getGroups()); if(operation != Operation.READ) { if (userContext.getRank().getInt() <= Rank.BASICUSER.getInt()) { Constraint mayNothing = query.createConstraint(query.createStepField(step, "number"), new Integer (-1)); 484 return new Authorization.QueryCheck(true, mayNothing); 485 } 486 } 487 } else if (step.getTableName().equals("mmbaseranks")) { newConstraint = query.createConstraint(query.createStepField(step, "rank"), FieldCompareConstraint.LESS_EQUAL, new Integer (userContext.getRank().getInt())); 489 } else { 490 continue; 491 } 492 493 if (constraint == null) { 494 constraint = newConstraint; 495 } else { 496 constraint = query.createConstraint(constraint, CompositeConstraint.LOGICAL_AND, newConstraint); 497 } 498 499 } 500 } 501 502 if (ac.contexts.size() == 0) { 503 if (ac.inverse) { 504 if (constraint == null) { 505 return Authorization.COMPLETE_CHECK; 506 } else { 507 return new Authorization.QueryCheck(true, constraint); 508 } 509 } else { 510 Constraint mayNothing = query.createConstraint(query.createStepField((Step) query.getSteps().get(0), "number"), new Integer (-1)); 512 return new Authorization.QueryCheck(true, mayNothing); 513 } 514 } 515 516 517 if (steps.size() * ac.contexts.size() < maxContextsInQuery) { 518 Iterator i = steps.iterator(); 519 while (i.hasNext()) { 520 Step step = (Step) i.next(); 521 StepField field = query.createStepField(step, "owner"); 522 Constraint newConstraint = query.createConstraint(field, ac.contexts); 523 if (ac.inverse) query.setInverse(newConstraint, true); 524 525 if (step.getTableName().equals("mmbaseusers")) { Users users = Users.getBuilder(); 527 Constraint own = query.createConstraint(query.createStepField(step, "number"), 528 new Integer (users.getUser(userContext.getIdentifier()).getNumber())); 529 newConstraint = query.createConstraint(newConstraint, CompositeConstraint.LOGICAL_OR, own); 530 } 531 532 533 if (constraint == null) { 534 constraint = newConstraint; 535 } else { 536 constraint = query.createConstraint(constraint, CompositeConstraint.LOGICAL_AND, newConstraint); 537 } 538 } 539 return new Authorization.QueryCheck(true, constraint); 540 } else { return Authorization.NO_CHECK; 542 } 543 544 } else { 545 return Authorization.NO_CHECK; 547 } 548 } 549 } 550 551 552 555 private final MMObjectNode getContextNode(MMObjectNode node) { 556 String s = node.getStringValue("owner"); 557 return getContextNode(s); 558 559 } 560 561 562 563 564 568 569 protected Collection getGroupsOrUsers(MMObjectNode contextNode, Operation operation, MMObjectBuilder groupsOrUsers) { 570 InsRel rights = RightsRel.getBuilder(); 571 572 BasicSearchQuery query = new BasicSearchQuery(); 573 Step step = query.addStep(this); 574 BasicStepField numberStepField = new BasicStepField(step, getField("number")); 575 BasicFieldValueConstraint numberConstraint = new BasicFieldValueConstraint(numberStepField, new Integer (contextNode.getNumber())); 576 577 BasicRelationStep relationStep = query.addRelationStep(rights, groupsOrUsers); 578 relationStep.setDirectionality(RelationStep.DIRECTIONS_DESTINATION); 579 580 BasicStepField operationStepField = new BasicStepField(relationStep, rights.getField("operation")); 581 BasicFieldValueConstraint operationConstraint = new BasicFieldValueConstraint(operationStepField, operation.toString()); 582 583 BasicCompositeConstraint constraint = new BasicCompositeConstraint(CompositeConstraint.LOGICAL_AND); 584 constraint.addChild(numberConstraint); 585 constraint.addChild(operationConstraint); 586 587 query.setConstraint(constraint); 588 589 query.addFields(relationStep.getNext()); 590 591 try { 592 return groupsOrUsers.getStorageConnector().getNodes(query, false); 593 } catch (SearchQueryException sqe) { 594 log.error(sqe.getMessage()); 595 return new ArrayList(); 596 } 597 598 } 599 600 603 protected Set getGroupsAndUsers(MMObjectNode contextNode, Operation operation) { 604 Set found = operationsCache.get(contextNode, operation); 605 if (found == null) { 606 found = new HashSet(); 607 608 found.addAll(getGroupsOrUsers(contextNode, operation, Users.getBuilder())); 609 found.addAll(getGroupsOrUsers(contextNode, operation, Groups.getBuilder())); 610 operationsCache.put(contextNode, operation, found); 611 } 612 613 return found; 614 } 615 616 617 618 protected final MMObjectNode getContextNode(String context) { 619 MMObjectNode contextNode = (MMObjectNode) contextCache.get(context); 620 if (contextNode == null && ! contextCache.contains(context)) { 621 try { 622 NodeSearchQuery query = new NodeSearchQuery(this); 623 BasicFieldValueConstraint constraint = new BasicFieldValueConstraint(query.getField(getField("name")), context); 624 query.setConstraint(constraint); 625 Iterator i = getNodes(query).iterator(); 626 if (i.hasNext()) { 627 contextNode = (MMObjectNode)i.next(); 628 } else { 629 if (! DEFAULT_CONTEXT.equals(context)) { 630 log.warn("Could not find context '" + context + "' using default context '" + DEFAULT_CONTEXT + "'"); 631 contextNode = getContextNode(DEFAULT_CONTEXT); 632 if (contextNode == null) { 633 log.error("Could not find default context '" + DEFAULT_CONTEXT + "'."); 634 } 635 } 636 } 637 } catch (SearchQueryException sqe) { 638 log.error(sqe.toString()); 639 contextNode = null; 640 641 } 642 contextCache.put(context, contextNode); 643 } 644 return contextNode; 645 646 } 647 648 649 650 653 public String getContext(User user, int nodeId) throws SecurityException { 654 MMObjectNode node = getNode(nodeId); 655 if (node == null) { 656 throw new SecurityException ("node #" + nodeId + " not found"); 657 } 658 return getContextNode(node).getStringValue("name"); 659 } 660 661 668 public MMObjectNode setContext(User user, int nodeId, String context) throws SecurityException { 669 MMObjectNode node = getNode(nodeId); 670 671 if (node.getStringValue("owner").equals(context)) return node; 676 677 if (node == null) { 678 throw new SecurityException ("node #" + nodeId + " not found"); 679 } 680 681 690 if (context == null || context.equals("")) { 691 log.warn("Tried to set context to '" + context + "' WRONG!"); 693 } else { 694 if (!getPossibleContexts(user, nodeId).contains(context)) { 695 throw new SecurityException ("could not set the context from '" + node.getStringValue("owner") + "' to '" + context + "' for node #" + nodeId + "(context name:" + context + " is not a valid context" + (context == null ? ", but null" : "") + ")"); 696 } 697 } 698 node.setValue("owner", context); 699 node.commit(); 700 return node; 701 } 702 703 708 public SortedSet getPossibleContexts(User user, int nodeId) throws SecurityException { 709 if (user.getRank().getInt() >= Rank.ADMIN_INT) { 710 return getAllContexts(); 712 } 713 714 MMObjectNode node = getNode(nodeId); 715 if (node == null) { 716 throw new SecurityException ("node #" + nodeId + " not found"); 717 } 718 if (node.getBuilder() instanceof Groups) { 719 return new TreeSet(); } 721 722 if (allContextsPossible) { 723 return getAllowingContexts(user, Operation.READ); 724 } else { 725 List possibleContexts = getContextNode(node).getRelatedNodes("mmbasecontexts", "allowed", RelationStep.DIRECTIONS_DESTINATION); 726 SortedSet set = new TreeSet(); 727 Iterator i = possibleContexts.iterator(); 728 while (i.hasNext()) { 729 MMObjectNode context = (MMObjectNode) i.next(); 730 if (mayDo(user, context.getNumber(), Operation.READ )) { 731 set.add(context.getStringValue("name")); 732 } else { 733 if (log.isDebugEnabled()) { 734 log.debug("context with name:" + context.getStringValue("name") + " could not be added to possible contexes, since we had no read rights"); 735 } 736 } 737 } 738 return set; 739 } 740 } 741 742 747 public SortedSet getPossibleContexts(User user) throws SecurityException { 748 if (user.getRank().getInt() >= Rank.ADMIN_INT) { 749 return getAllContexts(); 751 } else { 752 return getAllowingContexts(user, Operation.READ); 753 } 754 } 755 756 760 764 protected boolean allows(MMObjectNode contextNode, MMObjectNode groupOrUserNode, Operation operation) { 765 return getGroupsAndUsers(contextNode, operation).contains(groupOrUserNode); 766 } 767 768 774 protected boolean parentsAllow(MMObjectNode contextNode, MMObjectNode groupOrUserNode, Operation operation) { 775 try { 776 Groups groups = Groups.getBuilder(); 777 778 Set groupsAndUsers = getGroupsAndUsers(contextNode, operation); 779 Iterator i = groupsAndUsers.iterator(); 780 while (i.hasNext()) { 781 MMObjectNode containingGroup = (MMObjectNode) i.next(); 782 if (groups.contains(containingGroup, groupOrUserNode)) return true; 783 } 784 } catch (Throwable e) { 785 log.error(Logging.stackTrace(e)); 786 } 787 return false; 788 } 789 790 792 protected boolean mayGrant(MMObjectNode contextNode, MMObjectNode groupOrUserNode, Operation operation, MMObjectNode user) { 793 Users users = Users.getBuilder(); 794 if (users.getRank(user).getInt() >= Rank.ADMIN.getInt()) return true; Groups groups = Groups.getBuilder(); 796 797 if (groupOrUserNode.getBuilder() instanceof Groups) { 798 if (! groups.contains(groupOrUserNode, user.getNumber()) || users.getRank(user).getInt() <= Rank.BASICUSER.getInt()) return false; } else { 800 if (groupOrUserNode.equals(user)) return false; if (users.getRank(groupOrUserNode).getInt() >= users.getRank(user).getInt()) return false; } 803 return mayDo(user, contextNode, operation, true); } 805 806 807 808 810 protected boolean grant(MMObjectNode contextNode, MMObjectNode groupOrUserNode, Operation operation, MMObjectNode user) { 811 if (allows(contextNode, groupOrUserNode, operation)) return true; if (mayGrant(contextNode, groupOrUserNode, operation, user)) { 814 if (log.isServiceEnabled()) { 815 log.service("Granting right " + operation + " on context " + contextNode + " to group/user " + groupOrUserNode + " by " + user); 816 } 817 RightsRel rightsRel = RightsRel.getBuilder(); 818 MMObjectNode ownerContextNode = user.getNodeValue("defaultcontext"); 819 String ownerString; 820 if (ownerContextNode != null) { 821 ownerString = ownerContextNode.getStringValue("name"); 822 } else { 823 ownerString = DEFAULT_CONTEXT; 824 } 825 MMObjectNode newRight = rightsRel.getNewNode(ownerString, contextNode.getNumber(), groupOrUserNode.getNumber(), operation); 826 boolean res = newRight.insert(ownerString) > 0; 827 if (! res) { 828 log.error("Failed to grant " + newRight); 829 } else { 830 log.debug("Granted " + newRight); 831 } 832 return res; 833 834 } else { 835 log.service("Granting right " + operation + " on context " + contextNode + " to group/user " + groupOrUserNode + " by " + user + " failed because it it not allowed"); 836 return false; 837 } 838 } 839 840 841 844 public void setDefaults(MMObjectNode node) { 845 setUniqueValue(node, "name", "context"); 846 } 847 848 849 850 851 852 855 856 protected boolean mayRevoke(MMObjectNode contextNode, MMObjectNode groupOrUserNode, Operation operation, MMObjectNode user) { 857 Users users = Users.getBuilder(); 858 if (users.getRank(user).getInt() >= Rank.ADMIN.getInt()) return true; if (groupOrUserNode.getBuilder() instanceof Groups) { 860 if (! Groups.getBuilder().contains(groupOrUserNode, user.getNumber()) || users.getRank(user).getInt() <= Rank.BASICUSER.getInt()) return false; } else { 862 if (groupOrUserNode.equals(user)) return false; if (users.getRank(groupOrUserNode).getInt() >= users.getRank(user).getInt()) return false; } 865 return mayDo(user, contextNode, operation, true); } 867 868 869 870 872 873 protected boolean revoke(MMObjectNode contextNode, MMObjectNode groupOrUserNode, Operation operation, MMObjectNode user) { 874 if (!allows(contextNode, groupOrUserNode, operation)) return true; 876 if (mayRevoke(contextNode, groupOrUserNode, operation, user)) { 877 if (log.isServiceEnabled()) { 878 log.service("Revoking right " + operation + " on context " + contextNode + " to group " + groupOrUserNode + " by " + user); 879 } 880 RightsRel rights = RightsRel.getBuilder(); 881 NodeSearchQuery q = new NodeSearchQuery(rights); 882 BasicStepField snumber = q.getField(rights.getField("snumber")); 883 BasicStepField dnumber = q.getField(rights.getField("dnumber")); 884 BasicStepField op = q.getField(rights.getField("operation")); 885 BasicFieldValueConstraint c1 = new BasicFieldValueConstraint(snumber, new Integer (contextNode.getNumber())); 886 BasicFieldValueConstraint c2 = new BasicFieldValueConstraint(dnumber, new Integer (groupOrUserNode.getNumber())); 887 BasicFieldValueConstraint c3 = new BasicFieldValueConstraint(op, operation.toString()); 888 BasicCompositeConstraint cons = new BasicCompositeConstraint(BasicCompositeConstraint.LOGICAL_AND); 889 cons.addChild(c1); 890 cons.addChild(c2); 891 cons.addChild(c3); 892 q.setConstraint(cons); 893 try { 894 List r = rights.getNodes(q); 895 Iterator i = r.iterator(); 896 while (i.hasNext()) { 897 MMObjectNode right = (MMObjectNode) i.next(); 898 rights.removeNode(right); 899 } 900 } catch (Exception sqe) { 901 log.error(sqe.toString()); 902 return false; 903 } 904 return true; 905 } else { 906 log.service("Revoking right " + operation + " on context " + contextNode + " to group/user " + groupOrUserNode + " by " + user + " failed because it it not allowed"); 907 return false; 908 } 909 910 } 911 912 915 protected MMObjectNode getUserNode(UserContext user) { 916 Users users = Users.getBuilder(); 917 return users.getUser(user.getIdentifier()); 918 } 919 920 protected MMObjectNode getGroupOrUserNode(Parameters a) { 921 MMObjectNode groupOrUser = getNode(a.getString(PARAMETER_GROUPORUSER)); 922 if (groupOrUser == null) throw new IllegalArgumentException ("There is no node with id '" + a.get(PARAMETER_GROUPORUSER) + "'"); 923 MMObjectBuilder parent = groupOrUser.getBuilder(); 924 if (! (parent instanceof Groups || parent instanceof Users)) { 925 throw new IllegalArgumentException ("Node '" + a.get(PARAMETER_GROUPORUSER) + "' does not represent a group or a user"); 926 } 927 return groupOrUser; 928 } 929 930 protected Object executeFunction(MMObjectNode node, String function, List args) { 931 if (log.isDebugEnabled()) { 932 log.trace("executefunction of contexts " + function + " " + args); 933 } 934 if (function.equals("info")) { 935 List empty = new ArrayList(); 936 Map info = (Map) super.executeFunction(node, function, empty); 937 info.put("allows", "" + ALLOWS_PARAMETERS + " Wether operation may be done according to this context"); 938 info.put("parentsallow", "" + PARENTSALLOW_PARAMETERS + " Wether operation may be done by members of this group, also because of parents"); 939 info.put("grant", "" + GRANT_PARAMETERS + " Grant a right"); 940 info.put("revoke", "" + REVOKE_PARAMETERS + " Revoke a right"); 941 info.put("maygrant", "" + MAYGRANT_PARAMETERS + " Check if user may grant a right"); 942 info.put("mayrevoke", "" + MAYREVOKE_PARAMETERS + " Check if user may revoke a right"); 943 info.put("may", "" + MAY_PARAMETERS + " Checks a right for another user than yourself"); 944 945 if (args == null || args.size() == 0) { 946 return info; 947 } else { 948 return info.get(args.get(0)); 949 } 950 } else if (function.equals("allows")) { 951 Parameters a = Functions.buildParameters(ALLOWS_PARAMETERS, args); if (allows(node, getNode(a.getString(PARAMETER_GROUPORUSER)), Operation.getOperation(a.getString(PARAMETER_OPERATION)))) { 953 return Boolean.TRUE; 954 } else { 955 return Boolean.FALSE; 956 } 957 } else if (function.equals("parentsallow")) { Parameters a = Functions.buildParameters(PARENTSALLOW_PARAMETERS, args); 959 if (parentsAllow(node, getGroupOrUserNode(a), Operation.getOperation(a.getString(PARAMETER_OPERATION)))) { 960 return Boolean.TRUE; 961 } else { 962 return Boolean.FALSE; 963 } 964 } else if (function.equals("grant")) { 965 Parameters a = Functions.buildParameters(GRANT_PARAMETERS, args); 966 if (grant(node, getGroupOrUserNode(a), Operation.getOperation(a.getString(PARAMETER_OPERATION)), getUserNode((UserContext) a.get("user")))) { 967 return Boolean.TRUE; 968 } else { 969 return Boolean.FALSE; 970 } 971 } else if (function.equals("revoke")) { 972 Parameters a = Functions.buildParameters(REVOKE_PARAMETERS, args); 973 if (revoke(node, getGroupOrUserNode(a), Operation.getOperation(a.getString(PARAMETER_OPERATION)), getUserNode((UserContext) a.get("user")))) { 974 return Boolean.TRUE; 975 } else { 976 return Boolean.FALSE; 977 } 978 } else if (function.equals("maygrant")) { 979 Parameters a = Functions.buildParameters(MAYGRANT_PARAMETERS, args); 980 if (mayGrant(node, getGroupOrUserNode(a), Operation.getOperation(a.getString(PARAMETER_OPERATION)), getUserNode((UserContext) a.get("user")))) { 981 return Boolean.TRUE; 982 } else { 983 return Boolean.FALSE; 984 } 985 } else if (function.equals("mayrevoke")) { 986 Parameters a = Functions.buildParameters(MAYREVOKE_PARAMETERS, args); 987 if (mayRevoke(node, getGroupOrUserNode(a), Operation.getOperation(a.getString(PARAMETER_OPERATION)), getUserNode((UserContext) a.get("user")))) { 988 return Boolean.TRUE; 989 } else { 990 return Boolean.FALSE; 991 } 992 } else if (function.equals("may")) { 993 Parameters a = Functions.buildParameters(MAY_PARAMETERS, args); 994 MMObjectNode checkingUser = getUserNode((UserContext) a.get(Parameter.USER)); 995 if (checkingUser == null) { 996 throw new SecurityException ("Self was not supplied"); 997 } 998 MMObjectNode userToCheck = Users.getBuilder().getNode(a.getString("usertocheck")); 1000 if (userToCheck == null) { return Boolean.TRUE; 1004 } 1005 1006 if (Users.getBuilder().getRank(checkingUser).getInt() < Rank.ADMIN_INT) { 1008 if ((! mayDo(checkingUser, getContextNode(userToCheck), Operation.READ, true))) { 1009 throw new SecurityException ("You " + checkingUser + " / " + Users.getBuilder().getRank(checkingUser) + " are not allowed to check user '" + userToCheck + "' of context '" + getContextNode(userToCheck) + "' (you have no read rights on that context)"); 1010 } 1011 1012 } 1013 1015 if (mayDo(userToCheck, node, Operation.getOperation(a.getString(PARAMETER_OPERATION)), true)) { 1016 return Boolean.TRUE; 1017 } else { 1018 return Boolean.FALSE; 1019 } 1020 } else { 1021 return super.executeFunction(node, function, args); 1022 } 1023 } 1024 1025 1026 1027 1028 public String toString(MMObjectNode n) { 1029 return n.getStringValue("name"); 1030 } 1031 1032 private static class AllowingContexts { 1033 SortedSet contexts; 1034 boolean inverse; 1035 AllowingContexts(SortedSet c, boolean i) { 1036 contexts = c; 1037 inverse = i; 1038 } 1039 public String toString() { 1040 return (inverse ? "NOT IN " : "IN ") + contexts; 1041 } 1042 1043 } 1044 1045 1046 1047} 1048 | Popular Tags |