001package ca.uhn.fhir.rest.server.interceptor.auth; 002 003/* 004 * #%L 005 * HAPI FHIR - Server Framework 006 * %% 007 * Copyright (C) 2014 - 2022 Smile CDR, Inc. 008 * %% 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 * #L% 021 */ 022 023import ca.uhn.fhir.interceptor.model.RequestPartitionId; 024import ca.uhn.fhir.model.api.annotation.ResourceDef; 025import ca.uhn.fhir.model.primitive.IdDt; 026import ca.uhn.fhir.rest.api.Constants; 027import ca.uhn.fhir.rest.api.RestOperationTypeEnum; 028import ca.uhn.fhir.rest.api.server.RequestDetails; 029import com.google.common.collect.Lists; 030import org.apache.commons.lang3.Validate; 031import org.hl7.fhir.instance.model.api.IBaseResource; 032import org.hl7.fhir.instance.model.api.IIdType; 033 034import javax.annotation.Nonnull; 035import java.util.ArrayList; 036import java.util.Arrays; 037import java.util.Collection; 038import java.util.Collections; 039import java.util.HashSet; 040import java.util.List; 041import java.util.Optional; 042import java.util.Set; 043import java.util.concurrent.ConcurrentHashMap; 044 045import static org.apache.commons.lang3.ObjectUtils.defaultIfNull; 046 047public class RuleBuilder implements IAuthRuleBuilder { 048 049 private static final ConcurrentHashMap<Class<? extends IBaseResource>, String> ourTypeToName = new ConcurrentHashMap<>(); 050 private final ArrayList<IAuthRule> myRules; 051 private IAuthRuleBuilderRule myAllow; 052 private IAuthRuleBuilderRule myDeny; 053 054 public RuleBuilder() { 055 myRules = new ArrayList<>(); 056 } 057 058 @Override 059 public IAuthRuleBuilderRule allow() { 060 if (myAllow == null) { 061 myAllow = allow(null); 062 } 063 return myAllow; 064 } 065 066 @Override 067 public IAuthRuleBuilderRule allow(String theRuleName) { 068 return new RuleBuilderRule(PolicyEnum.ALLOW, theRuleName); 069 } 070 071 @Override 072 public IAuthRuleBuilderRuleOpClassifierFinished allowAll() { 073 return allowAll(null); 074 } 075 076 @Override 077 public IAuthRuleBuilderRuleOpClassifierFinished allowAll(String theRuleName) { 078 RuleImplOp rule = new RuleImplOp(theRuleName); 079 rule.setOp(RuleOpEnum.ALL); 080 rule.setMode(PolicyEnum.ALLOW); 081 myRules.add(rule); 082 return new RuleBuilderFinished(rule); 083 } 084 085 @Override 086 public List<IAuthRule> build() { 087 return myRules; 088 } 089 090 @Override 091 public IAuthRuleBuilderRule deny() { 092 if (myDeny == null) { 093 myDeny = deny(null); 094 } 095 return myDeny; 096 } 097 098 @Override 099 public IAuthRuleBuilderRule deny(String theRuleName) { 100 return new RuleBuilderRule(PolicyEnum.DENY, theRuleName); 101 } 102 103 @Override 104 public IAuthRuleBuilderRuleOpClassifierFinished denyAll() { 105 return denyAll(null); 106 } 107 108 @Override 109 public IAuthRuleBuilderRuleOpClassifierFinished denyAll(String theRuleName) { 110 RuleImplOp rule = new RuleImplOp(theRuleName); 111 rule.setOp(RuleOpEnum.ALL); 112 rule.setMode(PolicyEnum.DENY); 113 myRules.add(rule); 114 return new RuleBuilderFinished(rule); 115 } 116 117 private class RuleBuilderFinished implements IAuthRuleFinished, IAuthRuleBuilderRuleOpClassifierFinished, IAuthRuleBuilderRuleOpClassifierFinishedWithTenantId { 118 119 protected final BaseRule myOpRule; 120 private List<IAuthRuleTester> myTesters; 121 122 RuleBuilderFinished(BaseRule theRule) { 123 assert theRule != null; 124 myOpRule = theRule; 125 } 126 127 @Override 128 public IAuthRuleBuilder andThen() { 129 doBuildRule(); 130 return RuleBuilder.this; 131 } 132 133 @Override 134 public List<IAuthRule> build() { 135 doBuildRule(); 136 return myRules; 137 } 138 139 /** 140 * Subclasses may override 141 */ 142 protected void doBuildRule() { 143 // nothing 144 } 145 146 @Override 147 public IAuthRuleBuilderRuleOpClassifierFinishedWithTenantId forTenantIds(String... theTenantIds) { 148 return forTenantIds(Arrays.asList(defaultIfNull(theTenantIds, Constants.EMPTY_STRING_ARRAY))); 149 } 150 151 @Override 152 public IAuthRuleBuilderRuleOpClassifierFinishedWithTenantId forTenantIds(final Collection<String> theTenantIds) { 153 withTester(new TenantCheckingTester(theTenantIds, true)); 154 return this; 155 } 156 157 List<IAuthRuleTester> getTesters() { 158 if (myTesters == null) { 159 return Collections.emptyList(); 160 } 161 return myTesters; 162 } 163 164 @Override 165 public IAuthRuleBuilderRuleOpClassifierFinishedWithTenantId notForTenantIds(String... theTenantIds) { 166 return notForTenantIds(Arrays.asList(defaultIfNull(theTenantIds, Constants.EMPTY_STRING_ARRAY))); 167 } 168 169 @Override 170 public IAuthRuleBuilderRuleOpClassifierFinishedWithTenantId notForTenantIds(final Collection<String> theTenantIds) { 171 withTester(new TenantCheckingTester(theTenantIds, false)); 172 return this; 173 } 174 175 @Override 176 public IAuthRuleFinished withTester(IAuthRuleTester theTester) { 177 if (theTester != null) { 178 if (myTesters == null) { 179 myTesters = new ArrayList<>(); 180 } 181 myTesters.add(theTester); 182 myOpRule.addTester(theTester); 183 } 184 185 return this; 186 } 187 188 private class TenantCheckingTester implements IAuthRuleTester { 189 private final Collection<String> myTenantIds; 190 private final boolean myOutcome; 191 192 public TenantCheckingTester(Collection<String> theTenantIds, boolean theOutcome) { 193 myTenantIds = theTenantIds; 194 myOutcome = theOutcome; 195 } 196 197 @Override 198 public boolean matches(RestOperationTypeEnum theOperation, RequestDetails theRequestDetails, IIdType theInputResourceId, IBaseResource theInputResource) { 199 if (!myTenantIds.contains(theRequestDetails.getTenantId())) { 200 return !myOutcome; 201 } 202 203 return matchesResource(theInputResource); 204 } 205 206 @Override 207 public boolean matchesOutput(RestOperationTypeEnum theOperation, RequestDetails theRequestDetails, IBaseResource theOutputResource) { 208 if (!myTenantIds.contains(theRequestDetails.getTenantId())) { 209 return !myOutcome; 210 } 211 212 return matchesResource(theOutputResource); 213 } 214 215 private boolean matchesResource(IBaseResource theResource) { 216 if (theResource != null) { 217 RequestPartitionId partitionId = (RequestPartitionId) theResource.getUserData(Constants.RESOURCE_PARTITION_ID); 218 if (partitionId != null) { 219 String partitionNameOrNull = partitionId.getFirstPartitionNameOrNull(); 220 if (partitionNameOrNull == null || !myTenantIds.contains(partitionNameOrNull)) { 221 return !myOutcome; 222 } 223 } 224 } 225 226 return myOutcome; 227 } 228 } 229 } 230 231 private class RuleBuilderRule implements IAuthRuleBuilderRule { 232 233 private final PolicyEnum myRuleMode; 234 private final String myRuleName; 235 private RuleBuilderRuleOp myReadRuleBuilder; 236 private RuleBuilderRuleOp myWriteRuleBuilder; 237 238 RuleBuilderRule(PolicyEnum theRuleMode, String theRuleName) { 239 myRuleMode = theRuleMode; 240 myRuleName = theRuleName; 241 } 242 243 @Override 244 public IAuthRuleBuilderRuleConditional createConditional() { 245 return new RuleBuilderRuleConditional(RestOperationTypeEnum.CREATE); 246 } 247 248 @Override 249 public IAuthRuleBuilderRuleOpDelete delete() { 250 return new RuleBuilderRuleOp(RuleOpEnum.DELETE); 251 } 252 253 @Override 254 public IAuthRuleBuilderRuleConditional deleteConditional() { 255 return new RuleBuilderRuleConditional(RestOperationTypeEnum.DELETE); 256 } 257 258 @Override 259 public RuleBuilderFinished metadata() { 260 RuleImplOp rule = new RuleImplOp(myRuleName); 261 rule.setOp(RuleOpEnum.METADATA); 262 rule.setMode(myRuleMode); 263 myRules.add(rule); 264 return new RuleBuilderFinished(rule); 265 } 266 267 @Override 268 public IAuthRuleBuilderOperation operation() { 269 return new RuleBuilderRuleOperation(); 270 } 271 272 @Override 273 public IAuthRuleBuilderPatch patch() { 274 return new PatchBuilder(); 275 } 276 277 @Override 278 public IAuthRuleBuilderRuleOp read() { 279 if (myReadRuleBuilder == null) { 280 myReadRuleBuilder = new RuleBuilderRuleOp(RuleOpEnum.READ); 281 } 282 return myReadRuleBuilder; 283 } 284 285 @Override 286 public IAuthRuleBuilderRuleTransaction transaction() { 287 return new RuleBuilderRuleTransaction(); 288 } 289 290 @Override 291 public IAuthRuleBuilderRuleConditional updateConditional() { 292 return new RuleBuilderRuleConditional(RestOperationTypeEnum.UPDATE); 293 } 294 295 @Override 296 public IAuthRuleBuilderRuleOp write() { 297 if (myWriteRuleBuilder == null) { 298 myWriteRuleBuilder = new RuleBuilderRuleOp(RuleOpEnum.WRITE); 299 } 300 return myWriteRuleBuilder; 301 } 302 303 @Override 304 public IAuthRuleBuilderRuleOp create() { 305 if (myWriteRuleBuilder == null) { 306 myWriteRuleBuilder = new RuleBuilderRuleOp(RuleOpEnum.CREATE); 307 } 308 return myWriteRuleBuilder; 309 } 310 311 @Override 312 public IAuthRuleBuilderGraphQL graphQL() { 313 return new RuleBuilderGraphQL(); 314 } 315 316 @Override 317 public IAuthRuleBuilderRuleBulkExport bulkExport() { 318 return new RuleBuilderBulkExport(); 319 } 320 321 private class RuleBuilderRuleConditional implements IAuthRuleBuilderRuleConditional { 322 323 private AppliesTypeEnum myAppliesTo; 324 private Set<String> myAppliesToTypes; 325 private final RestOperationTypeEnum myOperationType; 326 327 RuleBuilderRuleConditional(RestOperationTypeEnum theOperationType) { 328 myOperationType = theOperationType; 329 } 330 331 @Override 332 public IAuthRuleBuilderRuleConditionalClassifier allResources() { 333 myAppliesTo = AppliesTypeEnum.ALL_RESOURCES; 334 return new RuleBuilderRuleConditionalClassifier(); 335 } 336 337 @Override 338 public IAuthRuleBuilderRuleConditionalClassifier resourcesOfType(Class<? extends IBaseResource> theType) { 339 Validate.notNull(theType, "theType must not be null"); 340 341 String typeName = toTypeName(theType); 342 return resourcesOfType(typeName); 343 } 344 345 @Override 346 public IAuthRuleBuilderRuleConditionalClassifier resourcesOfType(String theType) { 347 myAppliesTo = AppliesTypeEnum.TYPES; 348 myAppliesToTypes = Collections.singleton(theType); 349 return new RuleBuilderRuleConditionalClassifier(); 350 } 351 352 public class RuleBuilderRuleConditionalClassifier extends RuleBuilderFinished implements IAuthRuleBuilderRuleConditionalClassifier { 353 354 RuleBuilderRuleConditionalClassifier() { 355 super(new RuleImplConditional(myRuleName)); 356 } 357 358 @Override 359 protected void doBuildRule() { 360 RuleImplConditional rule = (RuleImplConditional) myOpRule; 361 rule.setMode(myRuleMode); 362 rule.setOperationType(myOperationType); 363 rule.setAppliesTo(myAppliesTo); 364 rule.setAppliesToTypes(myAppliesToTypes); 365 rule.addTesters(getTesters()); 366 myRules.add(rule); 367 368 } 369 } 370 371 } 372 373 private class RuleBuilderRuleOp implements IAuthRuleBuilderRuleOp, IAuthRuleBuilderRuleOpDelete { 374 375 private final RuleOpEnum myRuleOp; 376 private RuleBuilderRuleOpClassifier myInstancesBuilder; 377 private boolean myOnCascade; 378 private boolean myOnExpunge; 379 380 RuleBuilderRuleOp(RuleOpEnum theRuleOp) { 381 myRuleOp = theRuleOp; 382 } 383 384 @Override 385 public IAuthRuleBuilderRuleOpClassifier allResources() { 386 return new RuleBuilderRuleOpClassifier(AppliesTypeEnum.ALL_RESOURCES, null); 387 } 388 389 @Override 390 public IAuthRuleFinished instance(String theId) { 391 Validate.notBlank(theId, "theId must not be null or empty"); 392 return instance(new IdDt(theId)); 393 } 394 395 @Override 396 public IAuthRuleFinished instance(IIdType theId) { 397 Validate.notNull(theId, "theId must not be null"); 398 Validate.notBlank(theId.getValue(), "theId.getValue() must not be null or empty"); 399 Validate.notBlank(theId.getIdPart(), "theId must contain an ID part"); 400 401 List<IIdType> instances = Lists.newArrayList(theId); 402 return instances(instances); 403 } 404 405 @Override 406 public RuleBuilderFinished instances(Collection<IIdType> theInstances) { 407 Validate.notNull(theInstances, "theInstances must not be null"); 408 Validate.notEmpty(theInstances, "theInstances must not be empty"); 409 410 if (myInstancesBuilder == null) { 411 RuleBuilderRuleOpClassifier instancesBuilder = new RuleBuilderRuleOpClassifier(theInstances); 412 myInstancesBuilder = instancesBuilder; 413 return instancesBuilder.finished(); 414 } else { 415 return myInstancesBuilder.addInstances(theInstances); 416 } 417 } 418 419 420 @Override 421 public IAuthRuleBuilderRuleOpClassifier resourcesOfType(Class<? extends IBaseResource> theType) { 422 Validate.notNull(theType, "theType must not be null"); 423 String resourceName = toTypeName(theType); 424 return resourcesOfType(resourceName); 425 } 426 427 @Override 428 public IAuthRuleBuilderRuleOpClassifier resourcesOfType(String theType) { 429 Validate.notNull(theType, "theType must not be null"); 430 return new RuleBuilderRuleOpClassifier(AppliesTypeEnum.TYPES, Collections.singleton(theType)); 431 } 432 433 @Override 434 public IAuthRuleBuilderRuleOp onCascade() { 435 myOnCascade = true; 436 return this; 437 } 438 439 @Override 440 public IAuthRuleBuilderRuleOp onExpunge() { 441 myOnExpunge = true; 442 return this; 443 } 444 445 private class RuleBuilderRuleOpClassifier implements IAuthRuleBuilderRuleOpClassifier { 446 447 private final AppliesTypeEnum myAppliesTo; 448 private final Set<String> myAppliesToTypes; 449 private ClassifierTypeEnum myClassifierType; 450 private String myInCompartmentName; 451 private Collection<? extends IIdType> myInCompartmentOwners; 452 private Collection<IIdType> myAppliesToInstances; 453 private RuleImplOp myRule; 454 private AdditionalCompartmentSearchParameters myAdditionalSearchParamsForCompartmentTypes = new AdditionalCompartmentSearchParameters(); 455 456 /** 457 * Constructor 458 */ 459 RuleBuilderRuleOpClassifier(AppliesTypeEnum theAppliesTo, Set<String> theAppliesToTypes) { 460 super(); 461 myAppliesTo = theAppliesTo; 462 myAppliesToTypes = theAppliesToTypes; 463 } 464 465 /** 466 * Constructor 467 */ 468 RuleBuilderRuleOpClassifier(Collection<IIdType> theAppliesToInstances) { 469 myAppliesToInstances = theAppliesToInstances; 470 myAppliesTo = AppliesTypeEnum.INSTANCES; 471 myAppliesToTypes = null; 472 } 473 474 private RuleBuilderFinished finished() { 475 return finished(new RuleImplOp(myRuleName)); 476 } 477 478 private RuleBuilderFinished finished(RuleImplOp theRule) { 479 Validate.isTrue(myRule == null, "Can not call finished() twice"); 480 myRule = theRule; 481 theRule.setMode(myRuleMode); 482 theRule.setOp(myRuleOp); 483 theRule.setAppliesTo(myAppliesTo); 484 theRule.setAppliesToTypes(myAppliesToTypes); 485 theRule.setAppliesToInstances(myAppliesToInstances); 486 theRule.setClassifierType(myClassifierType); 487 theRule.setClassifierCompartmentName(myInCompartmentName); 488 theRule.setClassifierCompartmentOwners(myInCompartmentOwners); 489 theRule.setAppliesToDeleteCascade(myOnCascade); 490 theRule.setAppliesToDeleteExpunge(myOnExpunge); 491 theRule.setAdditionalSearchParamsForCompartmentTypes(myAdditionalSearchParamsForCompartmentTypes); 492 myRules.add(theRule); 493 494 return new RuleBuilderFinished(theRule); 495 } 496 497 @Override 498 public IAuthRuleBuilderRuleOpClassifierFinished inCompartment(String theCompartmentName, Collection<? extends IIdType> theOwners) { 499 return inCompartmentWithAdditionalSearchParams(theCompartmentName, theOwners, new AdditionalCompartmentSearchParameters()); 500 } 501 502 @Override 503 public IAuthRuleBuilderRuleOpClassifierFinished inCompartmentWithAdditionalSearchParams(String theCompartmentName, Collection<? extends IIdType> theOwners, AdditionalCompartmentSearchParameters theAdditionalTypeSearchParams) { 504 Validate.notBlank(theCompartmentName, "theCompartmentName must not be null"); 505 Validate.notNull(theOwners, "theOwners must not be null"); 506 Validate.noNullElements(theOwners, "theOwners must not contain any null elements"); 507 for (IIdType next : theOwners) { 508 validateOwner(next); 509 } 510 myInCompartmentName = theCompartmentName; 511 myInCompartmentOwners = theOwners; 512 myAdditionalSearchParamsForCompartmentTypes = theAdditionalTypeSearchParams; 513 myClassifierType = ClassifierTypeEnum.IN_COMPARTMENT; 514 return finished(); 515 } 516 517 @Override 518 public IAuthRuleBuilderRuleOpClassifierFinished inCompartment(String theCompartmentName, IIdType theOwner) { 519 return inCompartmentWithAdditionalSearchParams(theCompartmentName, theOwner, new AdditionalCompartmentSearchParameters()); 520 } 521 522 @Override 523 public IAuthRuleBuilderRuleOpClassifierFinished inCompartmentWithAdditionalSearchParams(String theCompartmentName, IIdType theOwner, AdditionalCompartmentSearchParameters theAdditionalTypeSearchParamNames) { 524 Validate.notBlank(theCompartmentName, "theCompartmentName must not be null"); 525 Validate.notNull(theOwner, "theOwner must not be null"); 526 validateOwner(theOwner); 527 myClassifierType = ClassifierTypeEnum.IN_COMPARTMENT; 528 myInCompartmentName = theCompartmentName; 529 myAdditionalSearchParamsForCompartmentTypes = theAdditionalTypeSearchParamNames; 530 Optional<RuleImplOp> oRule = findMatchingRule(); 531 if (oRule.isPresent()) { 532 RuleImplOp rule = oRule.get(); 533 rule.setAdditionalSearchParamsForCompartmentTypes(myAdditionalSearchParamsForCompartmentTypes); 534 rule.addClassifierCompartmentOwner(theOwner); 535 return new RuleBuilderFinished(rule); 536 } 537 myInCompartmentOwners = Collections.singletonList(theOwner); 538 return finished(); 539 } 540 541 542 private Optional<RuleImplOp> findMatchingRule() { 543 return myRules.stream() 544 .filter(RuleImplOp.class::isInstance) 545 .map(RuleImplOp.class::cast) 546 .filter(rule -> rule.matches(myRuleOp, myAppliesTo, myAppliesToInstances, myAppliesToTypes, myClassifierType, myInCompartmentName)) 547 .findFirst(); 548 } 549 550 private void validateOwner(IIdType theOwner) { 551 Validate.notBlank(theOwner.getIdPart(), "owner.getIdPart() must not be null or empty"); 552 Validate.notBlank(theOwner.getIdPart(), "owner.getResourceType() must not be null or empty"); 553 } 554 555 @Override 556 public IAuthRuleBuilderRuleOpClassifierFinished withAnyId() { 557 myClassifierType = ClassifierTypeEnum.ANY_ID; 558 return finished(); 559 } 560 561 @Override 562 public IAuthRuleBuilderRuleOpClassifierFinished withCodeInValueSet(@Nonnull String theSearchParameterName, @Nonnull String theValueSetUrl) { 563 SearchParameterAndValueSetRuleImpl rule = new SearchParameterAndValueSetRuleImpl(myRuleName); 564 rule.setSearchParameterName(theSearchParameterName); 565 rule.setValueSetUrl(theValueSetUrl); 566 rule.setWantCode(true); 567 return finished(rule); 568 } 569 570 @Override 571 public IAuthRuleFinished withCodeNotInValueSet(@Nonnull String theSearchParameterName, @Nonnull String theValueSetUrl) { 572 SearchParameterAndValueSetRuleImpl rule = new SearchParameterAndValueSetRuleImpl(myRuleName); 573 rule.setSearchParameterName(theSearchParameterName); 574 rule.setValueSetUrl(theValueSetUrl); 575 rule.setWantCode(false); 576 return finished(rule); 577 } 578 579 RuleBuilderFinished addInstances(Collection<IIdType> theInstances) { 580 myAppliesToInstances.addAll(theInstances); 581 return new RuleBuilderFinished(myRule); 582 } 583 } 584 585 } 586 587 private class RuleBuilderRuleOperation implements IAuthRuleBuilderOperation { 588 589 @Override 590 public IAuthRuleBuilderOperationNamed named(String theOperationName) { 591 Validate.notBlank(theOperationName, "theOperationName must not be null or empty"); 592 return new RuleBuilderRuleOperationNamed(theOperationName); 593 } 594 595 @Override 596 public IAuthRuleBuilderOperationNamed withAnyName() { 597 return new RuleBuilderRuleOperationNamed(null); 598 } 599 600 private class RuleBuilderRuleOperationNamed implements IAuthRuleBuilderOperationNamed { 601 602 private final String myOperationName; 603 604 RuleBuilderRuleOperationNamed(String theOperationName) { 605 if (theOperationName != null && !theOperationName.startsWith("$")) { 606 myOperationName = '$' + theOperationName; 607 } else { 608 myOperationName = theOperationName; 609 } 610 } 611 612 private OperationRule createRule() { 613 OperationRule rule = new OperationRule(myRuleName); 614 rule.setOperationName(myOperationName); 615 rule.setMode(myRuleMode); 616 return rule; 617 } 618 619 @Override 620 public IAuthRuleBuilderOperationNamedAndScoped onAnyInstance() { 621 OperationRule rule = createRule(); 622 rule.appliesToAnyInstance(); 623 return new RuleBuilderOperationNamedAndScoped(rule); 624 } 625 626 @Override 627 public IAuthRuleBuilderOperationNamedAndScoped atAnyLevel() { 628 OperationRule rule = createRule(); 629 rule.appliesAtAnyLevel(true); 630 return new RuleBuilderOperationNamedAndScoped(rule); 631 } 632 633 @Override 634 public IAuthRuleBuilderOperationNamedAndScoped onAnyType() { 635 OperationRule rule = createRule(); 636 rule.appliesToAnyType(); 637 return new RuleBuilderOperationNamedAndScoped(rule); 638 } 639 640 @Override 641 public IAuthRuleBuilderOperationNamedAndScoped onInstance(IIdType theInstanceId) { 642 Validate.notNull(theInstanceId, "theInstanceId must not be null"); 643 Validate.notBlank(theInstanceId.getResourceType(), "theInstanceId does not have a resource type"); 644 Validate.notBlank(theInstanceId.getIdPart(), "theInstanceId does not have an ID part"); 645 646 OperationRule rule = createRule(); 647 ArrayList<IIdType> ids = new ArrayList<>(); 648 ids.add(theInstanceId); 649 rule.appliesToInstances(ids); 650 return new RuleBuilderOperationNamedAndScoped(rule); 651 } 652 653 @Override 654 public IAuthRuleBuilderOperationNamedAndScoped onInstancesOfType(Class<? extends IBaseResource> theType) { 655 validateType(theType); 656 657 OperationRule rule = createRule(); 658 rule.appliesToInstancesOfType(toTypeSet(theType)); 659 return new RuleBuilderOperationNamedAndScoped(rule); 660 } 661 662 @Override 663 public IAuthRuleBuilderOperationNamedAndScoped onServer() { 664 OperationRule rule = createRule(); 665 rule.appliesToServer(); 666 return new RuleBuilderOperationNamedAndScoped(rule); 667 } 668 669 @Override 670 public IAuthRuleBuilderOperationNamedAndScoped onType(Class<? extends IBaseResource> theType) { 671 validateType(theType); 672 673 OperationRule rule = createRule(); 674 rule.appliesToTypes(toTypeSet(theType)); 675 return new RuleBuilderOperationNamedAndScoped(rule); 676 } 677 678 private HashSet<Class<? extends IBaseResource>> toTypeSet(Class<? extends IBaseResource> theType) { 679 HashSet<Class<? extends IBaseResource>> appliesToTypes = new HashSet<>(); 680 appliesToTypes.add(theType); 681 return appliesToTypes; 682 } 683 684 private void validateType(Class<? extends IBaseResource> theType) { 685 Validate.notNull(theType, "theType must not be null"); 686 } 687 688 private class RuleBuilderOperationNamedAndScoped implements IAuthRuleBuilderOperationNamedAndScoped { 689 690 private final OperationRule myRule; 691 692 RuleBuilderOperationNamedAndScoped(OperationRule theRule) { 693 myRule = theRule; 694 } 695 696 @Override 697 public IAuthRuleBuilderRuleOpClassifierFinished andAllowAllResponses() { 698 myRule.allowAllResponses(); 699 myRules.add(myRule); 700 return new RuleBuilderFinished(myRule); 701 } 702 703 @Override 704 public IAuthRuleBuilderRuleOpClassifierFinished andRequireExplicitResponseAuthorization() { 705 myRules.add(myRule); 706 return new RuleBuilderFinished(myRule); 707 } 708 } 709 710 } 711 712 } 713 714 private class RuleBuilderRuleTransaction implements IAuthRuleBuilderRuleTransaction { 715 716 @Override 717 public IAuthRuleBuilderRuleTransactionOp withAnyOperation() { 718 return new RuleBuilderRuleTransactionOp(); 719 } 720 721 private class RuleBuilderRuleTransactionOp implements IAuthRuleBuilderRuleTransactionOp { 722 723 @Override 724 public IAuthRuleBuilderRuleOpClassifierFinished andApplyNormalRules() { 725 // Allow transaction 726 RuleImplOp rule = new RuleImplOp(myRuleName); 727 rule.setMode(myRuleMode); 728 rule.setOp(RuleOpEnum.TRANSACTION); 729 rule.setTransactionAppliesToOp(TransactionAppliesToEnum.ANY_OPERATION); 730 myRules.add(rule); 731 return new RuleBuilderFinished(rule); 732 } 733 734 } 735 736 } 737 738 private class PatchBuilder implements IAuthRuleBuilderPatch { 739 740 PatchBuilder() { 741 super(); 742 } 743 744 @Override 745 public IAuthRuleFinished allRequests() { 746 BaseRule rule = new RuleImplPatch(myRuleName) 747 .setAllRequests(true) 748 .setMode(myRuleMode); 749 myRules.add(rule); 750 return new RuleBuilderFinished(rule); 751 } 752 } 753 754 private class RuleBuilderGraphQL implements IAuthRuleBuilderGraphQL { 755 @Override 756 public IAuthRuleFinished any() { 757 RuleImplOp rule = new RuleImplOp(myRuleName); 758 rule.setOp(RuleOpEnum.GRAPHQL); 759 rule.setMode(myRuleMode); 760 myRules.add(rule); 761 return new RuleBuilderFinished(rule); 762 } 763 } 764 765 private class RuleBuilderBulkExport implements IAuthRuleBuilderRuleBulkExport { 766 767 @Override 768 public IAuthRuleBuilderRuleBulkExportWithTarget groupExportOnGroup(@Nonnull String theFocusResourceId) { 769 RuleBulkExportImpl rule = new RuleBulkExportImpl(myRuleName); 770 rule.setAppliesToGroupExportOnGroup(theFocusResourceId); 771 rule.setMode(myRuleMode); 772 myRules.add(rule); 773 774 return new RuleBuilderBulkExportWithTarget(rule); 775 } 776 777 @Override 778 public IAuthRuleBuilderRuleBulkExportWithTarget patientExportOnGroup(@Nonnull String theFocusResourceId) { 779 RuleBulkExportImpl rule = new RuleBulkExportImpl(myRuleName); 780 rule.setAppliesToPatientExportOnGroup(theFocusResourceId); 781 rule.setMode(myRuleMode); 782 myRules.add(rule); 783 784 return new RuleBuilderBulkExportWithTarget(rule); 785 } 786 787 @Override 788 public IAuthRuleBuilderRuleBulkExportWithTarget systemExport() { 789 RuleBulkExportImpl rule = new RuleBulkExportImpl(myRuleName); 790 rule.setAppliesToSystem(); 791 rule.setMode(myRuleMode); 792 myRules.add(rule); 793 794 return new RuleBuilderBulkExportWithTarget(rule); 795 } 796 797 @Override 798 public IAuthRuleBuilderRuleBulkExportWithTarget any() { 799 RuleBulkExportImpl rule = new RuleBulkExportImpl(myRuleName); 800 rule.setAppliesToAny(); 801 rule.setMode(myRuleMode); 802 myRules.add(rule); 803 804 return new RuleBuilderBulkExportWithTarget(rule); 805 } 806 807 private class RuleBuilderBulkExportWithTarget extends RuleBuilderFinished implements IAuthRuleBuilderRuleBulkExportWithTarget { 808 private final RuleBulkExportImpl myRule; 809 810 private RuleBuilderBulkExportWithTarget(RuleBulkExportImpl theRule) { 811 super(theRule); 812 myRule = theRule; 813 814 } 815 816 @Override 817 public IAuthRuleBuilderRuleBulkExportWithTarget withResourceTypes(Collection<String> theResourceTypes) { 818 myRule.setResourceTypes(theResourceTypes); 819 return this; 820 } 821 } 822 } 823 } 824 825 private static String toTypeName(Class<? extends IBaseResource> theType) { 826 String retVal = ourTypeToName.get(theType); 827 if (retVal == null) { 828 ResourceDef resourceDef = theType.getAnnotation(ResourceDef.class); 829 retVal = resourceDef.name(); 830 Validate.notBlank(retVal, "Could not determine resource type of class %s", theType); 831 ourTypeToName.put(theType, retVal); 832 } 833 return retVal; 834 } 835 836}