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 Validate.isTrue(myRule == null, "Can not call finished() twice"); 476 myRule = new RuleImplOp(myRuleName); 477 myRule.setMode(myRuleMode); 478 myRule.setOp(myRuleOp); 479 myRule.setAppliesTo(myAppliesTo); 480 myRule.setAppliesToTypes(myAppliesToTypes); 481 myRule.setAppliesToInstances(myAppliesToInstances); 482 myRule.setClassifierType(myClassifierType); 483 myRule.setClassifierCompartmentName(myInCompartmentName); 484 myRule.setClassifierCompartmentOwners(myInCompartmentOwners); 485 myRule.setAppliesToDeleteCascade(myOnCascade); 486 myRule.setAppliesToDeleteExpunge(myOnExpunge); 487 myRule.setAdditionalSearchParamsForCompartmentTypes(myAdditionalSearchParamsForCompartmentTypes); 488 myRules.add(myRule); 489 490 return new RuleBuilderFinished(myRule); 491 } 492 493 @Override 494 public IAuthRuleBuilderRuleOpClassifierFinished inCompartment(String theCompartmentName, Collection<? extends IIdType> theOwners) { 495 return inCompartmentWithAdditionalSearchParams(theCompartmentName, theOwners, new AdditionalCompartmentSearchParameters()); 496 } 497 498 @Override 499 public IAuthRuleBuilderRuleOpClassifierFinished inCompartmentWithAdditionalSearchParams(String theCompartmentName, Collection<? extends IIdType> theOwners, AdditionalCompartmentSearchParameters theAdditionalTypeSearchParams) { 500 Validate.notBlank(theCompartmentName, "theCompartmentName must not be null"); 501 Validate.notNull(theOwners, "theOwners must not be null"); 502 Validate.noNullElements(theOwners, "theOwners must not contain any null elements"); 503 for (IIdType next : theOwners) { 504 validateOwner(next); 505 } 506 myInCompartmentName = theCompartmentName; 507 myInCompartmentOwners = theOwners; 508 myAdditionalSearchParamsForCompartmentTypes = theAdditionalTypeSearchParams; 509 myClassifierType = ClassifierTypeEnum.IN_COMPARTMENT; 510 return finished(); 511 } 512 513 @Override 514 public IAuthRuleBuilderRuleOpClassifierFinished inCompartment(String theCompartmentName, IIdType theOwner) { 515 return inCompartmentWithAdditionalSearchParams(theCompartmentName, theOwner, new AdditionalCompartmentSearchParameters()); 516 } 517 518 @Override 519 public IAuthRuleBuilderRuleOpClassifierFinished inCompartmentWithAdditionalSearchParams(String theCompartmentName, IIdType theOwner, AdditionalCompartmentSearchParameters theAdditionalTypeSearchParamNames) { 520 Validate.notBlank(theCompartmentName, "theCompartmentName must not be null"); 521 Validate.notNull(theOwner, "theOwner must not be null"); 522 validateOwner(theOwner); 523 myClassifierType = ClassifierTypeEnum.IN_COMPARTMENT; 524 myInCompartmentName = theCompartmentName; 525 myAdditionalSearchParamsForCompartmentTypes = theAdditionalTypeSearchParamNames; 526 Optional<RuleImplOp> oRule = findMatchingRule(); 527 if (oRule.isPresent()) { 528 RuleImplOp rule = oRule.get(); 529 rule.setAdditionalSearchParamsForCompartmentTypes(myAdditionalSearchParamsForCompartmentTypes); 530 rule.addClassifierCompartmentOwner(theOwner); 531 return new RuleBuilderFinished(rule); 532 } 533 myInCompartmentOwners = Collections.singletonList(theOwner); 534 return finished(); 535 } 536 537 538 private Optional<RuleImplOp> findMatchingRule() { 539 return myRules.stream() 540 .filter(RuleImplOp.class::isInstance) 541 .map(RuleImplOp.class::cast) 542 .filter(rule -> rule.matches(myRuleOp, myAppliesTo, myAppliesToInstances, myAppliesToTypes, myClassifierType, myInCompartmentName)) 543 .findFirst(); 544 } 545 546 private void validateOwner(IIdType theOwner) { 547 Validate.notBlank(theOwner.getIdPart(), "owner.getIdPart() must not be null or empty"); 548 Validate.notBlank(theOwner.getIdPart(), "owner.getResourceType() must not be null or empty"); 549 } 550 551 @Override 552 public IAuthRuleBuilderRuleOpClassifierFinished withAnyId() { 553 myClassifierType = ClassifierTypeEnum.ANY_ID; 554 return finished(); 555 } 556 557 RuleBuilderFinished addInstances(Collection<IIdType> theInstances) { 558 myAppliesToInstances.addAll(theInstances); 559 return new RuleBuilderFinished(myRule); 560 } 561 } 562 563 } 564 565 private class RuleBuilderRuleOperation implements IAuthRuleBuilderOperation { 566 567 @Override 568 public IAuthRuleBuilderOperationNamed named(String theOperationName) { 569 Validate.notBlank(theOperationName, "theOperationName must not be null or empty"); 570 return new RuleBuilderRuleOperationNamed(theOperationName); 571 } 572 573 @Override 574 public IAuthRuleBuilderOperationNamed withAnyName() { 575 return new RuleBuilderRuleOperationNamed(null); 576 } 577 578 private class RuleBuilderRuleOperationNamed implements IAuthRuleBuilderOperationNamed { 579 580 private final String myOperationName; 581 582 RuleBuilderRuleOperationNamed(String theOperationName) { 583 if (theOperationName != null && !theOperationName.startsWith("$")) { 584 myOperationName = '$' + theOperationName; 585 } else { 586 myOperationName = theOperationName; 587 } 588 } 589 590 private OperationRule createRule() { 591 OperationRule rule = new OperationRule(myRuleName); 592 rule.setOperationName(myOperationName); 593 rule.setMode(myRuleMode); 594 return rule; 595 } 596 597 @Override 598 public IAuthRuleBuilderOperationNamedAndScoped onAnyInstance() { 599 OperationRule rule = createRule(); 600 rule.appliesToAnyInstance(); 601 return new RuleBuilderOperationNamedAndScoped(rule); 602 } 603 604 @Override 605 public IAuthRuleBuilderOperationNamedAndScoped atAnyLevel() { 606 OperationRule rule = createRule(); 607 rule.appliesAtAnyLevel(true); 608 return new RuleBuilderOperationNamedAndScoped(rule); 609 } 610 611 @Override 612 public IAuthRuleBuilderOperationNamedAndScoped onAnyType() { 613 OperationRule rule = createRule(); 614 rule.appliesToAnyType(); 615 return new RuleBuilderOperationNamedAndScoped(rule); 616 } 617 618 @Override 619 public IAuthRuleBuilderOperationNamedAndScoped onInstance(IIdType theInstanceId) { 620 Validate.notNull(theInstanceId, "theInstanceId must not be null"); 621 Validate.notBlank(theInstanceId.getResourceType(), "theInstanceId does not have a resource type"); 622 Validate.notBlank(theInstanceId.getIdPart(), "theInstanceId does not have an ID part"); 623 624 OperationRule rule = createRule(); 625 ArrayList<IIdType> ids = new ArrayList<>(); 626 ids.add(theInstanceId); 627 rule.appliesToInstances(ids); 628 return new RuleBuilderOperationNamedAndScoped(rule); 629 } 630 631 @Override 632 public IAuthRuleBuilderOperationNamedAndScoped onInstancesOfType(Class<? extends IBaseResource> theType) { 633 validateType(theType); 634 635 OperationRule rule = createRule(); 636 rule.appliesToInstancesOfType(toTypeSet(theType)); 637 return new RuleBuilderOperationNamedAndScoped(rule); 638 } 639 640 @Override 641 public IAuthRuleBuilderOperationNamedAndScoped onServer() { 642 OperationRule rule = createRule(); 643 rule.appliesToServer(); 644 return new RuleBuilderOperationNamedAndScoped(rule); 645 } 646 647 @Override 648 public IAuthRuleBuilderOperationNamedAndScoped onType(Class<? extends IBaseResource> theType) { 649 validateType(theType); 650 651 OperationRule rule = createRule(); 652 rule.appliesToTypes(toTypeSet(theType)); 653 return new RuleBuilderOperationNamedAndScoped(rule); 654 } 655 656 private HashSet<Class<? extends IBaseResource>> toTypeSet(Class<? extends IBaseResource> theType) { 657 HashSet<Class<? extends IBaseResource>> appliesToTypes = new HashSet<>(); 658 appliesToTypes.add(theType); 659 return appliesToTypes; 660 } 661 662 private void validateType(Class<? extends IBaseResource> theType) { 663 Validate.notNull(theType, "theType must not be null"); 664 } 665 666 private class RuleBuilderOperationNamedAndScoped implements IAuthRuleBuilderOperationNamedAndScoped { 667 668 private final OperationRule myRule; 669 670 RuleBuilderOperationNamedAndScoped(OperationRule theRule) { 671 myRule = theRule; 672 } 673 674 @Override 675 public IAuthRuleBuilderRuleOpClassifierFinished andAllowAllResponses() { 676 myRule.allowAllResponses(); 677 myRules.add(myRule); 678 return new RuleBuilderFinished(myRule); 679 } 680 681 @Override 682 public IAuthRuleBuilderRuleOpClassifierFinished andRequireExplicitResponseAuthorization() { 683 myRules.add(myRule); 684 return new RuleBuilderFinished(myRule); 685 } 686 } 687 688 } 689 690 } 691 692 private class RuleBuilderRuleTransaction implements IAuthRuleBuilderRuleTransaction { 693 694 @Override 695 public IAuthRuleBuilderRuleTransactionOp withAnyOperation() { 696 return new RuleBuilderRuleTransactionOp(); 697 } 698 699 private class RuleBuilderRuleTransactionOp implements IAuthRuleBuilderRuleTransactionOp { 700 701 @Override 702 public IAuthRuleBuilderRuleOpClassifierFinished andApplyNormalRules() { 703 // Allow transaction 704 RuleImplOp rule = new RuleImplOp(myRuleName); 705 rule.setMode(myRuleMode); 706 rule.setOp(RuleOpEnum.TRANSACTION); 707 rule.setTransactionAppliesToOp(TransactionAppliesToEnum.ANY_OPERATION); 708 myRules.add(rule); 709 return new RuleBuilderFinished(rule); 710 } 711 712 } 713 714 } 715 716 private class PatchBuilder implements IAuthRuleBuilderPatch { 717 718 PatchBuilder() { 719 super(); 720 } 721 722 @Override 723 public IAuthRuleFinished allRequests() { 724 BaseRule rule = new RuleImplPatch(myRuleName) 725 .setAllRequests(true) 726 .setMode(myRuleMode); 727 myRules.add(rule); 728 return new RuleBuilderFinished(rule); 729 } 730 } 731 732 private class RuleBuilderGraphQL implements IAuthRuleBuilderGraphQL { 733 @Override 734 public IAuthRuleFinished any() { 735 RuleImplOp rule = new RuleImplOp(myRuleName); 736 rule.setOp(RuleOpEnum.GRAPHQL); 737 rule.setMode(myRuleMode); 738 myRules.add(rule); 739 return new RuleBuilderFinished(rule); 740 } 741 } 742 743 private class RuleBuilderBulkExport implements IAuthRuleBuilderRuleBulkExport { 744 745 @Override 746 public IAuthRuleBuilderRuleBulkExportWithTarget groupExportOnGroup(@Nonnull String theFocusResourceId) { 747 RuleBulkExportImpl rule = new RuleBulkExportImpl(myRuleName); 748 rule.setAppliesToGroupExportOnGroup(theFocusResourceId); 749 rule.setMode(myRuleMode); 750 myRules.add(rule); 751 752 return new RuleBuilderBulkExportWithTarget(rule); 753 } 754 755 @Override 756 public IAuthRuleBuilderRuleBulkExportWithTarget patientExportOnGroup(@Nonnull String theFocusResourceId) { 757 RuleBulkExportImpl rule = new RuleBulkExportImpl(myRuleName); 758 rule.setAppliesToPatientExportOnGroup(theFocusResourceId); 759 rule.setMode(myRuleMode); 760 myRules.add(rule); 761 762 return new RuleBuilderBulkExportWithTarget(rule); 763 } 764 765 @Override 766 public IAuthRuleBuilderRuleBulkExportWithTarget systemExport() { 767 RuleBulkExportImpl rule = new RuleBulkExportImpl(myRuleName); 768 rule.setAppliesToSystem(); 769 rule.setMode(myRuleMode); 770 myRules.add(rule); 771 772 return new RuleBuilderBulkExportWithTarget(rule); 773 } 774 775 @Override 776 public IAuthRuleBuilderRuleBulkExportWithTarget any() { 777 RuleBulkExportImpl rule = new RuleBulkExportImpl(myRuleName); 778 rule.setAppliesToAny(); 779 rule.setMode(myRuleMode); 780 myRules.add(rule); 781 782 return new RuleBuilderBulkExportWithTarget(rule); 783 } 784 785 private class RuleBuilderBulkExportWithTarget extends RuleBuilderFinished implements IAuthRuleBuilderRuleBulkExportWithTarget { 786 private final RuleBulkExportImpl myRule; 787 788 private RuleBuilderBulkExportWithTarget(RuleBulkExportImpl theRule) { 789 super(theRule); 790 myRule = theRule; 791 792 } 793 794 @Override 795 public IAuthRuleBuilderRuleBulkExportWithTarget withResourceTypes(Collection<String> theResourceTypes) { 796 myRule.setResourceTypes(theResourceTypes); 797 return this; 798 } 799 } 800 } 801 } 802 803 private static String toTypeName(Class<? extends IBaseResource> theType) { 804 String retVal = ourTypeToName.get(theType); 805 if (retVal == null) { 806 ResourceDef resourceDef = theType.getAnnotation(ResourceDef.class); 807 retVal = resourceDef.name(); 808 Validate.notBlank(retVal, "Could not determine resource type of class %s", theType); 809 ourTypeToName.put(theType, retVal); 810 } 811 return retVal; 812 } 813 814}