1 56 57 package org.opencrx.kernel.layer.model; 58 59 import java.util.ArrayList ; 60 import java.util.HashMap ; 61 import java.util.HashSet ; 62 import java.util.Iterator ; 63 import java.util.List ; 64 import java.util.ListIterator ; 65 import java.util.Map ; 66 import java.util.Set ; 67 68 import org.opencrx.kernel.generic.OpenCrxException; 69 import org.opencrx.kernel.generic.SecurityKeys; 70 import org.openmdx.application.log.AppLog; 71 import org.openmdx.base.exception.ServiceException; 72 import org.openmdx.compatibility.base.application.configuration.Configuration; 73 import org.openmdx.compatibility.base.collection.SparseList; 74 import org.openmdx.compatibility.base.dataprovider.cci.AttributeSelectors; 75 import org.openmdx.compatibility.base.dataprovider.cci.AttributeSpecifier; 76 import org.openmdx.compatibility.base.dataprovider.cci.DataproviderObject; 77 import org.openmdx.compatibility.base.dataprovider.cci.DataproviderObject_1_0; 78 import org.openmdx.compatibility.base.dataprovider.cci.DataproviderReply; 79 import org.openmdx.compatibility.base.dataprovider.cci.DataproviderRequest; 80 import org.openmdx.compatibility.base.dataprovider.cci.Dataprovider_1_0; 81 import org.openmdx.compatibility.base.dataprovider.cci.QualityOfService; 82 import org.openmdx.compatibility.base.dataprovider.cci.RequestCollection; 83 import org.openmdx.compatibility.base.dataprovider.cci.ServiceHeader; 84 import org.openmdx.compatibility.base.dataprovider.cci.SharedConfigurationEntries; 85 import org.openmdx.compatibility.base.dataprovider.cci.SystemAttributes; 86 import org.openmdx.compatibility.base.dataprovider.layer.model.Standard_1; 87 import org.openmdx.compatibility.base.dataprovider.spi.Layer_1_0; 88 import org.openmdx.compatibility.base.dataprovider.transport.adapter.Switch_1; 89 import org.openmdx.compatibility.base.naming.Path; 90 import org.openmdx.compatibility.base.query.FilterOperators; 91 import org.openmdx.compatibility.base.query.FilterProperty; 92 import org.openmdx.compatibility.base.query.Quantors; 93 import org.openmdx.kernel.exception.BasicException; 94 import org.openmdx.model1.accessor.basic.cci.ModelElement_1_0; 95 import org.openmdx.model1.accessor.basic.cci.Model_1_0; 96 import org.openmdx.uses.org.apache.commons.collections.map.LRUMap; 97 98 104 public class AccessControl_1 105 extends Standard_1 { 106 107 protected Path getUserIdentity( 109 Path accessPath, 110 String qualifiedPrincipalName 111 ) { 112 int pos = qualifiedPrincipalName.indexOf(":"); 113 String segmentName = null; 114 String principalName = null; 115 if(pos < 0) { 116 System.err.println("FATAL: object has illegal formatted owner (<realm segment>:<subject name>): " + qualifiedPrincipalName + "; path=" + accessPath.toXri()); 117 segmentName = "Root"; 118 principalName = qualifiedPrincipalName; 119 } 120 else { 121 segmentName = qualifiedPrincipalName.substring(0, pos); 122 principalName = qualifiedPrincipalName.substring(pos+1); 123 } 124 if(SecurityKeys.ADMIN_PRINCIPAL.equals(principalName) || SecurityKeys.LOADER_PRINCIPAL.equals(principalName)) { 127 principalName = principalName + SecurityKeys.ID_SEPARATOR + segmentName; 128 } 129 if(!principalName.endsWith(SecurityKeys.USER_SUFFIX)) { 132 principalName += "." + SecurityKeys.USER_SUFFIX; 133 } 134 Path principalIdentity = this.realmIdentity.getParent().getDescendant( 135 new String []{segmentName, "principal", principalName} 136 ); 137 return principalIdentity; 138 } 139 140 protected Path getGroupIdentity( 142 Path accessPath, 143 String qualifiedPrincipalName 144 ) { 145 int pos = qualifiedPrincipalName.indexOf(":"); 146 String segmentName = null; 147 String principalName = null; 148 if(pos < 0) { 149 System.err.println("FATAL: object has illegal formatted owner (<realm segment>:<subject name>): " + qualifiedPrincipalName + "; path=" + accessPath.toXri()); 150 segmentName = "Root"; 151 principalName = qualifiedPrincipalName; 152 } 153 else { 154 segmentName = qualifiedPrincipalName.substring(0, pos); 155 principalName = qualifiedPrincipalName.substring(pos+1); 156 } 157 Path principalIdentity = this.realmIdentity.getParent().getDescendant( 158 new String []{segmentName, "principal", principalName} 159 ); 160 return principalIdentity; 161 } 162 163 protected String getQualifiedPrincipalName( 165 Path accessPath, 166 String principalName 167 ) { 168 return accessPath.get(4) + ":" + principalName; 169 } 170 171 protected String getQualifiedPrincipalName( 173 Path principalIdentity 174 ) { 175 return principalIdentity.get(6) + ":" + principalIdentity.getBase(); 176 } 177 178 protected void completeOwningUserAndGroup( 180 ServiceHeader header, 181 DataproviderObject_1_0 object 182 ) throws ServiceException { 183 object.clearValues("owningUser"); 184 object.clearValues("owningGroup"); 185 if(object.values("owner").size() > 0) { 186 if((String )object.values("owner").get(0) == null) { 187 AppLog.error("Values of attribute owner are corrupt. Element at index 0 (owning user) is missing. Fix the database", object); 188 } 189 else { 190 object.values("owningUser").add( 191 this.getUserIdentity(object.path(), (String )object.values("owner").get(0)) 192 ); 193 } 194 } 195 for(int i = 1; i < object.values("owner").size(); i++) { 196 object.values("owningGroup").add( 197 this.getGroupIdentity(object.path(), (String )object.values("owner").get(i)) 198 ); 199 } 200 } 201 202 protected void completeObject( 204 ServiceHeader header, 205 DataproviderObject_1_0 object 206 ) throws ServiceException { 207 this.completeOwningUserAndGroup( 208 header, 209 object 210 ); 211 } 212 213 private void addToParentsCache( 215 DataproviderObject_1_0 object 216 ) { 217 if( 218 (object.getValues(SystemAttributes.OBJECT_CLASS) != null) && 219 (object.values(SystemAttributes.OBJECT_CLASS).size() > 0) 220 ) { 221 this.cachedParents.put( 222 object.path(), 223 new DataproviderObject(object) 224 ); 225 } 226 else { 227 AppLog.error("Missing object class. Object not added to cache", object.path()); 228 } 229 } 230 231 protected DataproviderReply completeReply( 233 ServiceHeader header, 234 DataproviderReply reply 235 ) throws ServiceException { 236 for(int i = 0; i < reply.getObjects().length; i++) { 237 DataproviderObject object = reply.getObjects()[i]; 238 this.completeObject( 240 header, 241 object 242 ); 243 } 244 return reply; 245 } 246 247 protected boolean isPrincipalGroup( 249 DataproviderObject_1_0 object 250 ) throws ServiceException { 251 String objectClass = (String )object.values(SystemAttributes.OBJECT_CLASS).get(0); 252 return this.model.isSubtypeOf( 253 objectClass, 254 "org:opencrx:security:realm1:PrincipalGroup" 255 ); 256 } 257 258 protected boolean isSecureObject( 260 DataproviderObject_1_0 object 261 ) throws ServiceException { 262 String objectClass = (String )object.values(SystemAttributes.OBJECT_CLASS).get(0); 263 if(objectClass == null) { 264 AppLog.error("Undefined object class", object.path()); 265 return true; 266 } 267 else { 268 return this.model.isSubtypeOf( 269 objectClass, 270 "org:opencrx:kernel:base:SecureObject" 271 ); 272 } 273 } 274 275 protected boolean isSecureObject( 277 ModelElement_1_0 type 278 ) throws ServiceException { 279 return this.model.isSubtypeOf( 280 type, 281 "org:opencrx:kernel:base:SecureObject" 282 ); 283 } 284 285 public RequestCollection getRunAsRootDelegation( 287 ) { 288 return new RequestCollection( 289 new ServiceHeader(SecurityKeys.ADMIN_PRINCIPAL + SecurityKeys.ID_SEPARATOR + "Root", null, false, new QualityOfService()), 290 this.router == null 291 ? this.getDelegation() 292 : this.router 293 ); 294 } 295 296 300 public void activate( 301 short id, 302 Configuration configuration, 303 Layer_1_0 delegation 304 ) throws Exception { 305 super.activate(id, configuration, delegation); 306 307 if(configuration.values(SharedConfigurationEntries.MODEL).size() > 0) { 309 this.model = (Model_1_0)configuration.values(SharedConfigurationEntries.MODEL).get(0); 310 } 311 else { 312 throw new ServiceException( 313 BasicException.Code.DEFAULT_DOMAIN, 314 BasicException.Code.INVALID_CONFIGURATION, 315 null, 316 "A model must be configured with options 'modelPackage' and 'packageImpl'" 317 ); 318 } 319 320 if(configuration.values(ConfigurationKeys.REALM_IDENTITY).size() > 0) { 322 this.realmIdentity = new Path((String )configuration.values(ConfigurationKeys.REALM_IDENTITY).get(0)); 323 } 324 else { 325 throw new ServiceException( 326 BasicException.Code.DEFAULT_DOMAIN, 327 BasicException.Code.INVALID_CONFIGURATION, 328 null, 329 "A realm identity must be configured with option 'realmIdentity'" 330 ); 331 } 332 333 SparseList dataproviderSource = configuration.values( 335 SharedConfigurationEntries.DATAPROVIDER_CONNECTION 336 ); 337 SparseList delegationPathSource = configuration.values( 338 SharedConfigurationEntries.DELEGATION_PATH 339 ); 340 if(delegationPathSource.isEmpty()){ 341 if(dataproviderSource.isEmpty()) { 342 this.router = this.getDelegation(); 343 } 344 else { 345 throw new ServiceException( 346 BasicException.Code.DEFAULT_DOMAIN, 347 BasicException.Code.INVALID_CONFIGURATION, 348 new BasicException.Parameter[]{}, 349 "The org:openmdx:compatibility:runtime1 model allowing to explore other dataproviders is deprecated." + 350 " Specifying " + SharedConfigurationEntries.DATAPROVIDER_CONNECTION + 351 " entries without their corresponding " + SharedConfigurationEntries.DELEGATION_PATH + 352 " is not supported" 353 ); 354 } 355 } 356 else { 357 List dataproviderTarget = new ArrayList (); 358 List delegationPathTarget = new ArrayList (); 359 for( 360 ListIterator dpi = delegationPathSource.populationIterator(); 361 dpi.hasNext(); 362 ) { 363 int i = dpi.nextIndex(); 364 Object dp = dataproviderSource.get(i); 365 if(dp == null) { 366 throw new ServiceException( 367 BasicException.Code.DEFAULT_DOMAIN, 368 BasicException.Code.INVALID_CONFIGURATION, 369 new BasicException.Parameter[]{ 370 new BasicException.Parameter(SharedConfigurationEntries.DELEGATION_PATH, delegationPathSource), 371 new BasicException.Parameter("index", i), 372 new BasicException.Parameter(SharedConfigurationEntries.DATAPROVIDER_CONNECTION, dataproviderSource) 373 }, 374 "The delegation path at the given index has no corresponding dataprovider counterpart" 375 ); 376 } 377 delegationPathTarget.add( 378 new Path((String )dpi.next()) 379 ); 380 dataproviderTarget.add(dp); 381 } 382 this.router = new Switch_1( 383 (Dataprovider_1_0[]) dataproviderTarget.toArray( 384 new Dataprovider_1_0[dataproviderTarget.size()] 385 ), 386 Path.toPathArray(delegationPathTarget), 387 this.getDelegation() 388 ); 389 } 390 } 391 392 397 private void assertSecurityContext( 398 ServiceHeader header, 399 DataproviderRequest request 400 ) throws ServiceException { 401 String principalName = header.getPrincipalChain().size() == 0 402 ? null 403 : (String )header.getPrincipalChain().get(0); 404 String realmName = SecurityKeys.ROOT_PRINCIPAL.equals(principalName) 405 ? "Root" 406 : request.path().get(4); 407 if(this.securityContexts.get(realmName) == null) { 408 this.securityContexts.put( 409 realmName, 410 new SecurityContext( 411 this, 412 this.realmIdentity.getParent().getChild(realmName) 413 ) 414 ); 415 } 416 this.currentSecurityContext = (SecurityContext)this.securityContexts.get(realmName); 417 this.requestingPrincipal = this.currentSecurityContext.getPrincipal(principalName); 418 if(this.requestingPrincipal == null) { 419 throw new ServiceException( 420 OpenCrxException.DOMAIN, 421 OpenCrxException.AUTHORIZATION_FAILURE_MISSING_PRINCIPAL, 422 new BasicException.Parameter[]{ 423 new BasicException.Parameter("principal", header.getPrincipalChain()), 424 new BasicException.Parameter("param0", header.getPrincipalChain()), 425 new BasicException.Parameter("param1", this.realmIdentity) 426 }, 427 "Requested principal not found." 428 ); 429 } 430 AppLog.detail("requesting principal", this.requestingPrincipal.path()); 431 this.requestingUser = this.currentSecurityContext.getGroup(this.requestingPrincipal); 432 } 433 434 private DataproviderObject_1_0 getCachedParent( 436 Path parentPath 437 ) throws ServiceException { 438 DataproviderObject_1_0 parent = (DataproviderObject_1_0)this.cachedParents.get(parentPath); 439 if(parent == null) { 440 parent = this.delegation.addGetRequest( 441 parentPath, 442 AttributeSelectors.ALL_ATTRIBUTES, 443 new AttributeSpecifier[]{} 444 ); 445 this.addToParentsCache(parent); 446 } 447 return parent; 448 } 449 450 454 public void prolog( 455 ServiceHeader header, 456 DataproviderRequest[] requests 457 ) throws ServiceException { 458 super.prolog(header, requests); 459 this.delegation = new RequestCollection( 460 header, 461 this.router == null 462 ? this.getDelegation() 463 : this.router 464 ); 465 } 466 467 471 public void epilog( 472 ServiceHeader header, 473 DataproviderRequest[] requests, 474 DataproviderReply[] replies 475 ) throws ServiceException { 476 super.epilog( 477 header, 478 requests, 479 replies 480 ); 481 this.requestingPrincipal = null; 482 } 483 484 488 public DataproviderReply create( 489 ServiceHeader header, 490 DataproviderRequest request 491 ) throws ServiceException { 492 493 this.assertSecurityContext( 494 header, 495 request 496 ); 497 498 DataproviderObject_1_0 parent = null; 500 if(request.path().size() >= 7) { 501 parent = this.getCachedParent(request.path().getPrefix(request.path().size()-2)); 502 if(this.isSecureObject(parent)) { 503 Set allowedPrincipals = new HashSet (); 504 if(parent.values("accessLevelUpdate").size() < 1) { 505 AppLog.error("missing attribute value for accessLevelUpdate", parent); 506 } 507 else { 508 allowedPrincipals = this.currentSecurityContext.getAllowedPrincipals( 509 this.requestingPrincipal, 510 this.requestingUser, 511 ((Number )parent.values("accessLevelUpdate").get(0)).shortValue() 512 ); 513 } 514 if(allowedPrincipals != null) { 515 allowedPrincipals.retainAll(parent.values("owner")); 516 if(allowedPrincipals.size() == 0) { 517 throw new ServiceException( 518 OpenCrxException.DOMAIN, 519 OpenCrxException.AUTHORIZATION_FAILURE_CREATE, 520 new BasicException.Parameter[]{ 521 new BasicException.Parameter("object", request.path()), 522 new BasicException.Parameter("param0", request.path()), 523 new BasicException.Parameter("param1", this.requestingPrincipal.path()) 524 }, 525 "No permission to create object." 526 ); 527 } 528 } 529 } 530 } 531 532 DataproviderObject newObject = request.object(); 534 535 if(this.isSecureObject(newObject)) { 537 538 String owningUser = null; 540 541 if( 543 (newObject.path().size() > USER_HOME_PATH_PATTERN.size()) && 544 newObject.path().getPrefix(USER_HOME_PATH_PATTERN.size()).isLike(USER_HOME_PATH_PATTERN) && 545 (parent.values("owner").size() > 0) 546 ) { 547 owningUser = (String )parent.values("owner").get(0); 548 } 549 else if(newObject.values("owningUser").size() > 0) { 551 owningUser = this.getQualifiedPrincipalName( 552 (Path)newObject.values("owningUser").get(0) 553 ); 554 } 555 else { 557 owningUser = newObject.values("owner").size() == 0 559 ? this.requestingUser == null 560 ? this.getQualifiedPrincipalName(newObject.path(), SecurityKeys.ADMIN_PRINCIPAL) 561 : this.getQualifiedPrincipalName(this.requestingUser.path()) 562 : (String )newObject.values("owner").get(0); 563 } 564 newObject.clearValues("owner").add(owningUser); 565 566 Set owningGroup = new HashSet (); 568 if(newObject.getValues("owningGroup") != null) { 569 for(Iterator i = newObject.values("owningGroup").iterator(); i.hasNext(); ) { 570 owningGroup.add( 571 this.getQualifiedPrincipalName((Path)i.next()) 572 ); 573 } 574 } 575 else { 576 DataproviderObject_1_0 userGroup = this.requestingPrincipal == null 577 ? null 578 : this.currentSecurityContext.getPrimaryGroup(this.requestingPrincipal); 579 owningGroup = new HashSet (); 580 if(parent != null) { 581 List ownersParent = new ArrayList (parent.values("owner")); 582 ownersParent.remove( 583 this.getQualifiedPrincipalName(newObject.path(), SecurityKeys.USER_GROUP_USERS) 584 ); 585 owningGroup.addAll( 586 ownersParent.subList(1, ownersParent.size()) 587 ); 588 } 589 owningGroup.add( 590 userGroup == null 591 ? this.getQualifiedPrincipalName(newObject.path(), "Unassigned") 592 : this.getQualifiedPrincipalName(userGroup.path()) 593 ); 594 } 595 newObject.values("owner").addAll(owningGroup); 596 597 newObject.clearValues("owningUser"); 598 newObject.clearValues("owningGroup"); 599 if( 601 (newObject.values("accessLevelBrowse").size() != 1) || 602 (((Number )newObject.values("accessLevelBrowse").get(0)).shortValue() == SecurityKeys.ACCESS_LEVEL_NA) 603 ) { 604 newObject.clearValues("accessLevelBrowse").add( 605 new Short (SecurityKeys.ACCESS_LEVEL_DEEP) 606 ); 607 } 608 if( 610 (newObject.values("accessLevelUpdate").size() != 1) || 611 (((Number )newObject.values("accessLevelUpdate").get(0)).shortValue() == SecurityKeys.ACCESS_LEVEL_NA) 612 ) { 613 newObject.clearValues("accessLevelUpdate").add( 614 new Short (SecurityKeys.ACCESS_LEVEL_BASIC) 615 ); 616 } 617 if( 619 (newObject.values("accessLevelDelete").size() != 1) || 620 (((Number )newObject.values("accessLevelDelete").get(0)).shortValue() == SecurityKeys.ACCESS_LEVEL_NA) 621 ) { 622 newObject.clearValues("accessLevelDelete").add( 623 new Short (SecurityKeys.ACCESS_LEVEL_BASIC) 624 ); 625 } 626 } 627 628 return this.completeReply( 629 header, 630 super.create(header, request) 631 ); 632 } 633 634 638 public DataproviderReply find( 639 ServiceHeader header, 640 DataproviderRequest request 641 ) throws ServiceException { 642 this.assertSecurityContext( 643 header, 644 request 645 ); 646 DataproviderObject_1_0 parent = this.getCachedParent(request.path().getParent()); 647 ModelElement_1_0 referencedType = this.model.getTypes(request.path())[2]; 648 if(this.isSecureObject(referencedType) && this.isSecureObject(parent)) { 649 Set allowedPrincipals = new HashSet (); 650 if(parent.values("accessLevelBrowse").size() < 1) { 651 AppLog.error("missing attribute value for accessLevelBrowse", parent); 652 } 653 else { 654 allowedPrincipals = this.currentSecurityContext.getAllowedPrincipals( 655 this.requestingPrincipal, 656 this.requestingUser, 657 ((Number )parent.values("accessLevelBrowse").get(0)).shortValue() 658 ); 659 } 660 if(allowedPrincipals != null) { 662 request.addAttributeFilterProperty( 663 new FilterProperty( 664 Quantors.THERE_EXISTS, 665 "owner", 666 FilterOperators.IS_IN, 667 allowedPrincipals.toArray(new String [allowedPrincipals.size()]) 668 ) 669 ); 670 } 671 } 672 return this.completeReply( 673 header, 674 super.find(header, request) 675 ); 676 } 677 678 682 public DataproviderReply get( 683 ServiceHeader header, 684 DataproviderRequest request 685 ) throws ServiceException { 686 this.assertSecurityContext( 687 header, 688 request 689 ); 690 DataproviderReply reply = super.get( 691 header, 692 request 693 ); 694 if(request.path().size() >= 7) { 695 DataproviderObject_1_0 parent = this.getCachedParent( 696 request.path().getPrefix(request.path().size()-2) 697 ); 698 ModelElement_1_0 referencedType = this.model.getTypes(request.path())[2]; 699 if(this.isSecureObject(referencedType) && this.isSecureObject(parent)) { 700 Set allowedPrincipals = new HashSet (); 701 if(parent.values("accessLevelBrowse").size() < 1) { 702 AppLog.error("missing attribute value for accessLevelBrowse", parent); 703 } 704 else { 705 allowedPrincipals = this.currentSecurityContext.getAllowedPrincipals( 706 this.requestingPrincipal, 707 this.requestingUser, 708 ((Number )parent.values("accessLevelBrowse").get(0)).shortValue() 709 ); 710 } 711 if(allowedPrincipals != null) { 712 allowedPrincipals.retainAll(reply.getObject().values("owner")); 713 if(allowedPrincipals.size() > 0) { 714 return this.completeReply( 715 header, 716 reply 717 ); 718 } 719 else { 720 throw new ServiceException( 721 BasicException.Code.DEFAULT_DOMAIN, 722 BasicException.Code.AUTHORIZATION_FAILURE, 723 new BasicException.Parameter[]{ 724 new BasicException.Parameter("path", request.path()), 725 new BasicException.Parameter("param0", request.path()), 726 new BasicException.Parameter("param1", this.requestingPrincipal.path()) 727 }, 728 "no permission to access requested object." 729 ); 730 } 731 } 732 } 733 } 734 return this.completeReply( 735 header, 736 reply 737 ); 738 } 739 740 744 public DataproviderReply remove( 745 ServiceHeader header, 746 DataproviderRequest request 747 ) throws ServiceException { 748 749 this.assertSecurityContext( 750 header, 751 request 752 ); 753 754 DataproviderObject_1_0 existingObject = this.delegation.addGetRequest( 755 request.path(), 756 AttributeSelectors.ALL_ATTRIBUTES, 757 new AttributeSpecifier[]{} 758 ); 759 if(this.isSecureObject(existingObject)) { 760 761 Set allowedPrincipals = new HashSet (); 763 if(existingObject.values("accessLevelDelete").size() < 1) { 764 AppLog.error("missing attribute value for accessLevelDelete", existingObject); 765 } 766 else { 767 allowedPrincipals = this.currentSecurityContext.getAllowedPrincipals( 768 this.requestingPrincipal, 769 this.requestingUser, 770 ((Number )existingObject.values("accessLevelDelete").get(0)).shortValue() 771 ); 772 } 773 if(allowedPrincipals != null) { 774 allowedPrincipals.retainAll(existingObject.values("owner")); 775 if(allowedPrincipals.size() == 0) { 777 throw new ServiceException( 778 OpenCrxException.DOMAIN, 779 OpenCrxException.AUTHORIZATION_FAILURE_DELETE, 780 new BasicException.Parameter[]{ 781 new BasicException.Parameter("object", request.path()), 782 new BasicException.Parameter("param0", request.path()), 783 new BasicException.Parameter("param1", this.requestingPrincipal.path()) 784 }, 785 "No permission to delete requested object." 786 ); 787 } 788 } 789 } 790 791 this.cachedParents.remove(request.path()); 792 return this.completeReply( 793 header, 794 super.remove(header, request) 795 ); 796 } 797 798 802 public DataproviderReply replace( 803 ServiceHeader header, 804 DataproviderRequest request 805 ) throws ServiceException { 806 this.assertSecurityContext( 807 header, 808 request 809 ); 810 DataproviderObject_1_0 existingObject = this.delegation.addGetRequest( 811 request.path(), 812 AttributeSelectors.ALL_ATTRIBUTES, 813 new AttributeSpecifier[]{} 814 ); 815 if(this.isSecureObject(existingObject)) { 816 817 Set allowedPrincipals = new HashSet (); 819 if(existingObject.values("accessLevelUpdate").size() < 1) { 820 AppLog.error("missing attribute value for accessLevelUpdate", existingObject); 821 } 822 else { 823 allowedPrincipals = this.currentSecurityContext.getAllowedPrincipals( 824 this.requestingPrincipal, 825 this.requestingUser, 826 ((Number )existingObject.values("accessLevelUpdate").get(0)).shortValue() 827 ); 828 } 829 if(allowedPrincipals != null) { 830 allowedPrincipals.retainAll(existingObject.values("owner")); 831 if(allowedPrincipals.size() == 0) { 833 throw new ServiceException( 834 OpenCrxException.DOMAIN, 835 OpenCrxException.AUTHORIZATION_FAILURE_UPDATE, 836 new BasicException.Parameter[]{ 837 new BasicException.Parameter("object", request.path()), 838 new BasicException.Parameter("param0", request.path()), 839 new BasicException.Parameter("param1", this.requestingPrincipal.path()) 840 }, 841 "No permission to update requested object." 842 ); 843 } 844 } 845 DataproviderObject replacement = request.object(); 847 848 replacement.clearValues("owner"); 851 852 String owningUser = null; 855 if(replacement.values("owningUser").size() > 0) { 856 owningUser = this.getQualifiedPrincipalName((Path)replacement.values("owningUser").get(0)); 857 } 858 else { 859 owningUser = existingObject.values("owner").size() == 0 861 ? this.requestingUser == null ? this.getQualifiedPrincipalName(replacement.path(), SecurityKeys.ADMIN_PRINCIPAL) : this.getQualifiedPrincipalName(this.requestingUser.path()) 862 : (String )existingObject.values("owner").get(0); 863 } 864 replacement.values("owner").add(owningUser); 865 866 List owningGroup = new ArrayList (); 868 if(replacement.getValues("owningGroup") != null) { 869 for(Iterator i = replacement.values("owningGroup").iterator(); i.hasNext(); ) { 871 Path group = (Path)i.next(); 872 if(group != null) { 873 owningGroup.add( 874 this.getQualifiedPrincipalName(group) 875 ); 876 } 877 } 878 } 879 else { 880 if(existingObject.values("owner").size() > 1) { 882 owningGroup.addAll( 883 existingObject.values("owner").subList(1, existingObject.values("owner").size()) 884 ); 885 } 886 } 887 replacement.values("owner").addAll(owningGroup); 888 replacement.clearValues("owningUser"); 889 replacement.clearValues("owningGroup"); 890 } 891 892 this.cachedParents.remove(request.path()); 893 return this.completeReply( 894 header, 895 super.replace(header, request) 896 ); 897 } 898 899 private static final Path USER_HOME_PATH_PATTERN = 901 new Path("xri:@openmdx:org.opencrx.kernel.home1/provider/:*/segment/:*/userHome/:*"); 902 903 private Path realmIdentity = null; 904 protected RequestCollection delegation = null; 905 private Dataprovider_1_0 router = null; 906 private Model_1_0 model = null; 907 908 private Map securityContexts = new HashMap (); 910 911 private SecurityContext currentSecurityContext = null; 913 private DataproviderObject_1_0 requestingPrincipal = null; 915 private DataproviderObject_1_0 requestingUser = null; 917 918 private static final int MAX_CACHED_PARENTS = 1000; 920 private Map cachedParents = new LRUMap(MAX_CACHED_PARENTS); 921 922 } 923 924 | Popular Tags |