1 17 package org.alfresco.repo.security.permissions.impl.acegi; 18 19 import java.util.ArrayList ; 20 import java.util.BitSet ; 21 import java.util.Collection ; 22 import java.util.HashSet ; 23 import java.util.Iterator ; 24 import java.util.List ; 25 import java.util.Set ; 26 import java.util.StringTokenizer ; 27 28 import net.sf.acegisecurity.AccessDeniedException; 29 import net.sf.acegisecurity.Authentication; 30 import net.sf.acegisecurity.ConfigAttribute; 31 import net.sf.acegisecurity.ConfigAttributeDefinition; 32 import net.sf.acegisecurity.afterinvocation.AfterInvocationProvider; 33 34 import org.alfresco.repo.search.SimpleResultSetMetaData; 35 import org.alfresco.repo.security.permissions.impl.SimplePermissionReference; 36 import org.alfresco.service.cmr.repository.ChildAssociationRef; 37 import org.alfresco.service.cmr.repository.NodeRef; 38 import org.alfresco.service.cmr.repository.NodeService; 39 import org.alfresco.service.cmr.repository.StoreRef; 40 import org.alfresco.service.cmr.search.LimitBy; 41 import org.alfresco.service.cmr.search.PermissionEvaluationMode; 42 import org.alfresco.service.cmr.search.ResultSet; 43 import org.alfresco.service.cmr.security.AccessStatus; 44 import org.alfresco.service.cmr.security.AuthenticationService; 45 import org.alfresco.service.cmr.security.PermissionService; 46 import org.alfresco.service.namespace.NamespacePrefixResolver; 47 import org.alfresco.service.namespace.QName; 48 import org.aopalliance.intercept.MethodInvocation; 49 import org.apache.commons.logging.Log; 50 import org.apache.commons.logging.LogFactory; 51 import org.springframework.beans.factory.InitializingBean; 52 53 public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider, InitializingBean 54 { 55 private static Log log = LogFactory.getLog(ACLEntryAfterInvocationProvider.class); 56 57 private static final String AFTER_ACL_NODE = "AFTER_ACL_NODE"; 58 59 private static final String AFTER_ACL_PARENT = "AFTER_ACL_PARENT"; 60 61 private PermissionService permissionService; 62 63 private NamespacePrefixResolver nspr; 64 65 private NodeService nodeService; 66 67 private AuthenticationService authenticationService; 68 69 public ACLEntryAfterInvocationProvider() 70 { 71 super(); 72 } 73 74 public void setPermissionService(PermissionService permissionService) 75 { 76 this.permissionService = permissionService; 77 } 78 79 public PermissionService getPermissionService() 80 { 81 return permissionService; 82 } 83 84 public NamespacePrefixResolver getNamespacePrefixResolver() 85 { 86 return nspr; 87 } 88 89 public void setNamespacePrefixResolver(NamespacePrefixResolver nspr) 90 { 91 this.nspr = nspr; 92 } 93 94 public NodeService getNodeService() 95 { 96 return nodeService; 97 } 98 99 public void setNodeService(NodeService nodeService) 100 { 101 this.nodeService = nodeService; 102 } 103 104 public AuthenticationService getAuthenticationService() 105 { 106 return authenticationService; 107 } 108 109 public void setAuthenticationService(AuthenticationService authenticationService) 110 { 111 this.authenticationService = authenticationService; 112 } 113 114 public void afterPropertiesSet() throws Exception 115 { 116 if (permissionService == null) 117 { 118 throw new IllegalArgumentException ("There must be a permission service"); 119 } 120 if (nspr == null) 121 { 122 throw new IllegalArgumentException ("There must be a namespace service"); 123 } 124 if (nodeService == null) 125 { 126 throw new IllegalArgumentException ("There must be a node service"); 127 } 128 if (authenticationService == null) 129 { 130 throw new IllegalArgumentException ("There must be an authentication service"); 131 } 132 133 } 134 135 public Object decide(Authentication authentication, Object object, ConfigAttributeDefinition config, 136 Object returnedObject) throws AccessDeniedException 137 { 138 if (log.isDebugEnabled()) 139 { 140 MethodInvocation mi = (MethodInvocation) object; 141 log.debug("Method: " + mi.getMethod().toString()); 142 } 143 try 144 { 145 if (authenticationService.isCurrentUserTheSystemUser()) 146 { 147 if (log.isDebugEnabled()) 148 { 149 log.debug("Allowing system user access"); 150 } 151 return returnedObject; 152 } 153 else if (returnedObject == null) 154 { 155 if (log.isDebugEnabled()) 156 { 157 log.debug("Allowing null object access"); 158 } 159 return null; 160 } 161 else if (StoreRef.class.isAssignableFrom(returnedObject.getClass())) 162 { 163 if (log.isDebugEnabled()) 164 { 165 log.debug("Store access"); 166 } 167 return decide(authentication, object, config, nodeService.getRootNode((StoreRef) returnedObject)) 168 .getStoreRef(); 169 } 170 else if (NodeRef.class.isAssignableFrom(returnedObject.getClass())) 171 { 172 if (log.isDebugEnabled()) 173 { 174 log.debug("Node access"); 175 } 176 return decide(authentication, object, config, (NodeRef) returnedObject); 177 } 178 else if (ChildAssociationRef.class.isAssignableFrom(returnedObject.getClass())) 179 { 180 if (log.isDebugEnabled()) 181 { 182 log.debug("Child Association access"); 183 } 184 return decide(authentication, object, config, (ChildAssociationRef) returnedObject); 185 } 186 else if (ResultSet.class.isAssignableFrom(returnedObject.getClass())) 187 { 188 if (log.isDebugEnabled()) 189 { 190 log.debug("Result Set access"); 191 } 192 return decide(authentication, object, config, (ResultSet) returnedObject); 193 } 194 else if (Collection .class.isAssignableFrom(returnedObject.getClass())) 195 { 196 if (log.isDebugEnabled()) 197 { 198 log.debug("Collection Access"); 199 } 200 return decide(authentication, object, config, (Collection ) returnedObject); 201 } 202 else if (returnedObject.getClass().isArray()) 203 { 204 if (log.isDebugEnabled()) 205 { 206 log.debug("Array Access"); 207 } 208 return decide(authentication, object, config, (Object []) returnedObject); 209 } 210 else 211 { 212 if (log.isDebugEnabled()) 213 { 214 log.debug("Uncontrolled object - access allowed for " + object.getClass().getName()); 215 } 216 return returnedObject; 217 } 218 } 219 catch (AccessDeniedException ade) 220 { 221 if (log.isDebugEnabled()) 222 { 223 log.debug("Access denied"); 224 ade.printStackTrace(); 225 } 226 throw ade; 227 } 228 catch (RuntimeException re) 229 { 230 if (log.isDebugEnabled()) 231 { 232 log.debug("Access denied by runtime exception"); 233 re.printStackTrace(); 234 } 235 throw re; 236 } 237 238 } 239 240 public NodeRef decide(Authentication authentication, Object object, ConfigAttributeDefinition config, 241 NodeRef returnedObject) throws AccessDeniedException 242 243 { 244 if (returnedObject == null) 245 { 246 return null; 247 } 248 249 List <ConfigAttributeDefintion> supportedDefinitions = extractSupportedDefinitions(config); 250 251 if (supportedDefinitions.size() == 0) 252 { 253 return returnedObject; 254 } 255 256 for (ConfigAttributeDefintion cad : supportedDefinitions) 257 { 258 NodeRef testNodeRef = null; 259 260 if (cad.typeString.equals(AFTER_ACL_NODE)) 261 { 262 testNodeRef = returnedObject; 263 } 264 else if (cad.typeString.equals(AFTER_ACL_PARENT)) 265 { 266 testNodeRef = nodeService.getPrimaryParent(returnedObject).getParentRef(); 267 } 268 269 if ((testNodeRef != null) 270 && (permissionService.hasPermission(testNodeRef, cad.required.toString()) == AccessStatus.DENIED)) 271 { 272 throw new AccessDeniedException("Access Denied"); 273 } 274 275 } 276 277 return returnedObject; 278 } 279 280 private List <ConfigAttributeDefintion> extractSupportedDefinitions(ConfigAttributeDefinition config) 281 { 282 List <ConfigAttributeDefintion> definitions = new ArrayList <ConfigAttributeDefintion>(); 283 Iterator iter = config.getConfigAttributes(); 284 285 while (iter.hasNext()) 286 { 287 ConfigAttribute attr = (ConfigAttribute) iter.next(); 288 289 if (this.supports(attr)) 290 { 291 definitions.add(new ConfigAttributeDefintion(attr)); 292 } 293 294 } 295 return definitions; 296 } 297 298 public ChildAssociationRef decide(Authentication authentication, Object object, ConfigAttributeDefinition config, 299 ChildAssociationRef returnedObject) throws AccessDeniedException 300 301 { 302 if (returnedObject == null) 303 { 304 return null; 305 } 306 307 List <ConfigAttributeDefintion> supportedDefinitions = extractSupportedDefinitions(config); 308 309 if (supportedDefinitions.size() == 0) 310 { 311 return returnedObject; 312 } 313 314 for (ConfigAttributeDefintion cad : supportedDefinitions) 315 { 316 NodeRef testNodeRef = null; 317 318 if (cad.typeString.equals(AFTER_ACL_NODE)) 319 { 320 testNodeRef = ((ChildAssociationRef) returnedObject).getChildRef(); 321 } 322 else if (cad.typeString.equals(AFTER_ACL_PARENT)) 323 { 324 testNodeRef = ((ChildAssociationRef) returnedObject).getParentRef(); 325 } 326 327 if ((testNodeRef != null) 328 && (permissionService.hasPermission(testNodeRef, cad.required.toString()) == AccessStatus.DENIED)) 329 { 330 throw new AccessDeniedException("Access Denied"); 331 } 332 333 } 334 335 return returnedObject; 336 } 337 338 public ResultSet decide(Authentication authentication, Object object, ConfigAttributeDefinition config, 339 ResultSet returnedObject) throws AccessDeniedException 340 341 { 342 if (returnedObject == null) 343 { 344 return null; 345 } 346 347 FilteringResultSet filteringResultSet = new FilteringResultSet(returnedObject); 348 349 350 List <ConfigAttributeDefintion> supportedDefinitions = extractSupportedDefinitions(config); 351 352 Integer maxSize = null; 353 if(returnedObject.getResultSetMetaData().getSearchParameters().getLimitBy() == LimitBy.FINAL_SIZE) 354 { 355 maxSize = new Integer (returnedObject.getResultSetMetaData().getSearchParameters().getLimit()); 356 } 357 358 if (supportedDefinitions.size() == 0) 359 { 360 if(maxSize == null) 361 { 362 return returnedObject; 363 } 364 else if (returnedObject.length() > maxSize.intValue()) 365 { 366 for(int i = 0; i < maxSize.intValue(); i++) 367 { 368 filteringResultSet.setIncluded(i, true); 369 } 370 filteringResultSet.setResultSetMetaData(new SimpleResultSetMetaData(LimitBy.FINAL_SIZE, PermissionEvaluationMode.EAGER, returnedObject.getResultSetMetaData().getSearchParameters())); 371 } 372 else 373 { 374 for(int i = 0; i < maxSize.intValue(); i++) 375 { 376 filteringResultSet.setIncluded(i, true); 377 } 378 filteringResultSet.setResultSetMetaData(new SimpleResultSetMetaData(LimitBy.UNLIMITED, PermissionEvaluationMode.EAGER, returnedObject.getResultSetMetaData().getSearchParameters())); 379 } 380 } 381 382 383 384 for (int i = 0; i < returnedObject.length(); i++) 385 { 386 filteringResultSet.setIncluded(i, true); 388 389 for (ConfigAttributeDefintion cad : supportedDefinitions) 390 { 391 NodeRef testNodeRef = null; 392 if (cad.typeString.equals(AFTER_ACL_NODE)) 393 { 394 testNodeRef = returnedObject.getNodeRef(i); 395 } 396 else if (cad.typeString.equals(AFTER_ACL_PARENT)) 397 { 398 testNodeRef = returnedObject.getChildAssocRef(i).getParentRef(); 399 } 400 401 if (filteringResultSet.getIncluded(i) 402 && (testNodeRef != null) 403 && (permissionService.hasPermission(testNodeRef, cad.required.toString()) == AccessStatus.DENIED)) 404 { 405 filteringResultSet.setIncluded(i, false); 406 } 407 } 408 409 411 if((maxSize != null) && (filteringResultSet.length() > maxSize.intValue())) 412 { 413 filteringResultSet.setIncluded(i, false); 415 filteringResultSet.setResultSetMetaData(new SimpleResultSetMetaData(LimitBy.FINAL_SIZE, PermissionEvaluationMode.EAGER, returnedObject.getResultSetMetaData().getSearchParameters())); 416 return filteringResultSet; 417 } 418 } 419 filteringResultSet.setResultSetMetaData(new SimpleResultSetMetaData(LimitBy.UNLIMITED, PermissionEvaluationMode.EAGER, returnedObject.getResultSetMetaData().getSearchParameters())); 420 return filteringResultSet; 421 } 422 423 public Collection decide(Authentication authentication, Object object, ConfigAttributeDefinition config, 424 Collection returnedObject) throws AccessDeniedException 425 426 { 427 if (returnedObject == null) 428 { 429 return null; 430 } 431 432 List <ConfigAttributeDefintion> supportedDefinitions = extractSupportedDefinitions(config); 433 434 if (supportedDefinitions.size() == 0) 435 { 436 return returnedObject; 437 } 438 439 Set <Object > removed = new HashSet <Object >(); 440 441 if (log.isDebugEnabled()) 442 { 443 log.debug("Entries are " + supportedDefinitions); 444 } 445 446 for (Object nextObject : returnedObject) 447 { 448 boolean allowed = true; 449 for (ConfigAttributeDefintion cad : supportedDefinitions) 450 { 451 NodeRef testNodeRef = null; 452 453 if (cad.typeString.equals(AFTER_ACL_NODE)) 454 { 455 if (StoreRef.class.isAssignableFrom(nextObject.getClass())) 456 { 457 testNodeRef = nodeService.getRootNode((StoreRef) nextObject); 458 if (log.isDebugEnabled()) 459 { 460 log.debug("\tNode Test on store " + nodeService.getPath(testNodeRef)); 461 } 462 } 463 else if (NodeRef.class.isAssignableFrom(nextObject.getClass())) 464 { 465 testNodeRef = (NodeRef) nextObject; 466 if (log.isDebugEnabled()) 467 { 468 log.debug("\tNode Test on node " + nodeService.getPath(testNodeRef)); 469 } 470 } 471 else if (ChildAssociationRef.class.isAssignableFrom(nextObject.getClass())) 472 { 473 testNodeRef = ((ChildAssociationRef) nextObject).getChildRef(); 474 if (log.isDebugEnabled()) 475 { 476 log.debug("\tNode Test on child association ref using " + nodeService.getPath(testNodeRef)); 477 } 478 } 479 else 480 { 481 throw new ACLEntryVoterException( 482 "The specified parameter is not a collection of NodeRefs or ChildAssociationRefs"); 483 } 484 } 485 else if (cad.typeString.equals(AFTER_ACL_PARENT)) 486 { 487 if (StoreRef.class.isAssignableFrom(nextObject.getClass())) 488 { 489 testNodeRef = null; 491 if (log.isDebugEnabled()) 492 { 493 log.debug("\tParent Test on store "); 494 } 495 } 496 else if (NodeRef.class.isAssignableFrom(nextObject.getClass())) 497 { 498 testNodeRef = nodeService.getPrimaryParent((NodeRef) nextObject).getParentRef(); 499 if (log.isDebugEnabled()) 500 { 501 log.debug("\tParent test on node " + nodeService.getPath(testNodeRef)); 502 } 503 } 504 else if (ChildAssociationRef.class.isAssignableFrom(nextObject.getClass())) 505 { 506 testNodeRef = ((ChildAssociationRef) nextObject).getParentRef(); 507 if (log.isDebugEnabled()) 508 { 509 log.debug("\tParent Test on child association ref using " 510 + nodeService.getPath(testNodeRef)); 511 } 512 } 513 else 514 { 515 throw new ACLEntryVoterException( 516 "The specified parameter is not a collection of NodeRefs or ChildAssociationRefs"); 517 } 518 } 519 520 if (allowed 521 && (testNodeRef != null) 522 && (permissionService.hasPermission(testNodeRef, cad.required.toString()) == AccessStatus.DENIED)) 523 { 524 allowed = false; 525 } 526 } 527 if (!allowed) 528 { 529 removed.add(nextObject); 530 } 531 } 532 for (Object toRemove : removed) 533 { 534 while (returnedObject.remove(toRemove)) 535 ; 536 } 537 return returnedObject; 538 } 539 540 public Object [] decide(Authentication authentication, Object object, ConfigAttributeDefinition config, 541 Object [] returnedObject) throws AccessDeniedException 542 543 { 544 BitSet incudedSet = new BitSet (returnedObject.length); 545 546 if (returnedObject == null) 547 { 548 return null; 549 } 550 551 List <ConfigAttributeDefintion> supportedDefinitions = extractSupportedDefinitions(config); 552 553 if (supportedDefinitions.size() == 0) 554 { 555 return returnedObject; 556 } 557 558 for (int i = 0, l = returnedObject.length; i < l; i++) 559 { 560 Object current = returnedObject[i]; 561 for (ConfigAttributeDefintion cad : supportedDefinitions) 562 { 563 incudedSet.set(i, true); 564 NodeRef testNodeRef = null; 565 if (cad.typeString.equals(AFTER_ACL_NODE)) 566 { 567 if (StoreRef.class.isAssignableFrom(current.getClass())) 568 { 569 testNodeRef = nodeService.getRootNode((StoreRef) current); 570 } 571 else if (NodeRef.class.isAssignableFrom(current.getClass())) 572 { 573 testNodeRef = (NodeRef) current; 574 } 575 else if (ChildAssociationRef.class.isAssignableFrom(current.getClass())) 576 { 577 testNodeRef = ((ChildAssociationRef) current).getChildRef(); 578 } 579 else 580 { 581 throw new ACLEntryVoterException("The specified array is not of NodeRef or ChildAssociationRef"); 582 } 583 } 584 585 else if (cad.typeString.equals(AFTER_ACL_PARENT)) 586 { 587 if (StoreRef.class.isAssignableFrom(current.getClass())) 588 { 589 testNodeRef = null; 590 } 591 else if (NodeRef.class.isAssignableFrom(current.getClass())) 592 { 593 testNodeRef = nodeService.getPrimaryParent((NodeRef) current).getParentRef(); 594 } 595 else if (ChildAssociationRef.class.isAssignableFrom(current.getClass())) 596 { 597 testNodeRef = ((ChildAssociationRef) current).getParentRef(); 598 } 599 else 600 { 601 throw new ACLEntryVoterException("The specified array is not of NodeRef or ChildAssociationRef"); 602 } 603 } 604 605 if (incudedSet.get(i) 606 && (testNodeRef != null) 607 && (permissionService.hasPermission(testNodeRef, cad.required.toString()) == AccessStatus.DENIED)) 608 { 609 incudedSet.set(i, false); 610 } 611 612 } 613 } 614 615 if (incudedSet.cardinality() == returnedObject.length) 616 { 617 return returnedObject; 618 } 619 else 620 { 621 Object [] answer = new Object [incudedSet.cardinality()]; 622 for (int i = incudedSet.nextSetBit(0), p = 0; i >= 0; i = incudedSet.nextSetBit(++i), p++) 623 { 624 answer[p] = returnedObject[i]; 625 } 626 return answer; 627 } 628 } 629 630 public boolean supports(ConfigAttribute attribute) 631 { 632 if ((attribute.getAttribute() != null) 633 && (attribute.getAttribute().startsWith(AFTER_ACL_NODE) || attribute.getAttribute().startsWith( 634 AFTER_ACL_PARENT))) 635 { 636 return true; 637 } 638 else 639 { 640 return false; 641 } 642 } 643 644 public boolean supports(Class clazz) 645 { 646 return (MethodInvocation.class.isAssignableFrom(clazz)); 647 } 648 649 private class ConfigAttributeDefintion 650 { 651 652 String typeString; 653 654 SimplePermissionReference required; 655 656 ConfigAttributeDefintion(ConfigAttribute attr) 657 { 658 659 StringTokenizer st = new StringTokenizer (attr.getAttribute(), ".", false); 660 if (st.countTokens() != 3) 661 { 662 throw new ACLEntryVoterException("There must be three . separated tokens in each config attribute"); 663 } 664 typeString = st.nextToken(); 665 String qNameString = st.nextToken(); 666 String permissionString = st.nextToken(); 667 668 if (!(typeString.equals(AFTER_ACL_NODE) || typeString.equals(AFTER_ACL_PARENT))) 669 { 670 throw new ACLEntryVoterException("Invalid type: must be ACL_NODE or ACL_PARENT"); 671 } 672 673 QName qName = QName.createQName(qNameString, nspr); 674 675 required = new SimplePermissionReference(qName, permissionString); 676 } 677 } 678 } 679 | Popular Tags |