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}