diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_1_0/3756-tester-api.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_1_0/3756-tester-api.yaml new file mode 100644 index 00000000000..2511bdd6ba1 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_1_0/3756-tester-api.yaml @@ -0,0 +1,4 @@ +--- +type: change +issue: 3756 +title: "The IAuthRuleTester api has changed and now uses a parameter object for flexibility." diff --git a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/matcher/AuthorizationSearchParamMatcher.java b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/matcher/AuthorizationSearchParamMatcher.java index bca89bbb920..331775c6c76 100644 --- a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/matcher/AuthorizationSearchParamMatcher.java +++ b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/matcher/AuthorizationSearchParamMatcher.java @@ -23,8 +23,14 @@ package ca.uhn.fhir.jpa.searchparam.matcher; import ca.uhn.fhir.jpa.searchparam.MatchUrlService; import ca.uhn.fhir.rest.server.interceptor.auth.IAuthorizationSearchParamMatcher; import org.hl7.fhir.instance.model.api.IBaseResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +/** + * Adapter from {@link SearchParamMatcher} to our authorization version. + */ public class AuthorizationSearchParamMatcher implements IAuthorizationSearchParamMatcher { + private static final Logger ourLog = LoggerFactory.getLogger(AuthorizationSearchParamMatcher.class); private final SearchParamMatcher mySearchParamMatcher; public AuthorizationSearchParamMatcher(SearchParamMatcher mySearchParamMatcher) { @@ -36,18 +42,20 @@ public class AuthorizationSearchParamMatcher implements IAuthorizationSearchPara try { InMemoryMatchResult inMemoryMatchResult = mySearchParamMatcher.match(theCriteria, theResource, null); if (!inMemoryMatchResult.supported()) { - return new MatchResult(Match.UNSUPPORTED, inMemoryMatchResult.getUnsupportedReason()); + return MatchResult.buildUnsupported(inMemoryMatchResult.getUnsupportedReason()); } if (inMemoryMatchResult.matched()) { - return new MatchResult(Match.MATCH, null); + return MatchResult.buildMatched(); } else { - return new MatchResult(Match.NO_MATCH, null); + return MatchResult.buildUnmatched(); } } catch (MatchUrlService.UnrecognizedSearchParameterException e) { - // wipmb revisit this design - // The matcher treats a bad expression as InvalidRequestException because it assumes it is during SearchParameter storage. - // Instead, we adapt this to UNSUPPORTED during authorization. We may be applying to all types, and this filter won't match. - return new MatchResult(Match.UNSUPPORTED, e.getMessage()); + // The matcher treats a bad expression as InvalidRequestException because + // it assumes it is during SearchParameter storage. + // Instead, we adapt this to UNSUPPORTED during authorization. + // We may be applying to all types, and this filter won't match. + ourLog.info("Unsupported filter {} applied to resource: {}", theCriteria, e.getMessage()); + return MatchResult.buildUnsupported(e.getMessage()); } } } diff --git a/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/auth/FhirQueryRuleImplTest.java b/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/auth/FhirQueryRuleImplTest.java index ef9157f3b65..61e827a07d1 100644 --- a/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/auth/FhirQueryRuleImplTest.java +++ b/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/auth/FhirQueryRuleImplTest.java @@ -94,7 +94,7 @@ class FhirQueryRuleImplTest implements ITestDataBuilder { .andThen().build().get(0); when(myMatcher.match(ArgumentMatchers.eq("Patient?family=Smith"), ArgumentMatchers.same(myResource))) - .thenReturn(IAuthorizationSearchParamMatcher.MatchResult.makeMatched()); + .thenReturn(IAuthorizationSearchParamMatcher.MatchResult.buildMatched()); // when AuthorizationInterceptor.Verdict verdict = applyRuleToResource(myResource); @@ -112,7 +112,7 @@ class FhirQueryRuleImplTest implements ITestDataBuilder { .inCompartmentWithFilter("patient", myResource.getIdElement().withResourceType("Patient"), "family=smi") .andThen().build().get(0); when(myMatcher.match(ArgumentMatchers.eq("Patient?family=smi"), ArgumentMatchers.same(myResource))) - .thenReturn(IAuthorizationSearchParamMatcher.MatchResult.makeUnmatched()); + .thenReturn(IAuthorizationSearchParamMatcher.MatchResult.buildUnmatched()); // when AuthorizationInterceptor.Verdict verdict = applyRuleToResource(myResource); @@ -133,7 +133,7 @@ class FhirQueryRuleImplTest implements ITestDataBuilder { .inCompartmentWithFilter("patient", myResource.getIdElement().withResourceType("Patient"), "code=28521000087105") .andThen().build().get(0); when(myMatcher.match("Observation?code=28521000087105", myResource2)) - .thenReturn(IAuthorizationSearchParamMatcher.MatchResult.makeUnmatched()); + .thenReturn(IAuthorizationSearchParamMatcher.MatchResult.buildUnmatched()); // when AuthorizationInterceptor.Verdict verdict = applyRuleToResource(myResource2); @@ -152,7 +152,7 @@ class FhirQueryRuleImplTest implements ITestDataBuilder { .withFilter("code=12") .andThen().build().get(0); when(myMatcher.match("Observation?code=12", myResource2)) - .thenReturn(IAuthorizationSearchParamMatcher.MatchResult.makeUnmatched()); + .thenReturn(IAuthorizationSearchParamMatcher.MatchResult.buildUnmatched()); // when AuthorizationInterceptor.Verdict verdict = applyRuleToResource(myResource2); @@ -171,7 +171,7 @@ class FhirQueryRuleImplTest implements ITestDataBuilder { .withFilter("code=28521000087105") .andThen().build().get(0); when(myMatcher.match("Observation?code=28521000087105", myResource2)) - .thenReturn(IAuthorizationSearchParamMatcher.MatchResult.makeMatched()); + .thenReturn(IAuthorizationSearchParamMatcher.MatchResult.buildMatched()); // when AuthorizationInterceptor.Verdict verdict = applyRuleToResource(myResource2); @@ -200,7 +200,7 @@ class FhirQueryRuleImplTest implements ITestDataBuilder { myRule = (FhirQueryRuleImpl) new RuleBuilder().allow().read().resourcesOfType("Patient") .inCompartmentWithFilter("patient", myResource.getIdElement().withResourceType("Patient"), "family=smi").andThen().build().get(0); when(myMatcher.match("Patient?family=smi", myResource)) - .thenReturn(IAuthorizationSearchParamMatcher.MatchResult.makeUnsupported("I'm broken unsupported chain XXX")); + .thenReturn(IAuthorizationSearchParamMatcher.MatchResult.buildUnsupported("I'm broken unsupported chain XXX")); // when AuthorizationInterceptor.Verdict verdict = applyRuleToResource(myResource); @@ -217,7 +217,7 @@ class FhirQueryRuleImplTest implements ITestDataBuilder { myRule = (FhirQueryRuleImpl) new RuleBuilder().deny().read().resourcesOfType("Patient") .inCompartmentWithFilter("patient", myResource.getIdElement().withResourceType("Patient"), "family=smi").andThen().build().get(0); when(myMatcher.match("Patient?family=smi", myResource)) - .thenReturn(IAuthorizationSearchParamMatcher.MatchResult.makeUnsupported("I'm broken unsupported chain XXX")); + .thenReturn(IAuthorizationSearchParamMatcher.MatchResult.buildUnsupported("I'm broken unsupported chain XXX")); // when AuthorizationInterceptor.Verdict verdict = applyRuleToResource(myResource); diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/BaseRule.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/BaseRule.java index ace323139f2..22e4d39a1ac 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/BaseRule.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/BaseRule.java @@ -29,7 +29,6 @@ import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IIdType; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.List; @@ -54,20 +53,24 @@ abstract class BaseRule implements IAuthRule { theTesters.forEach(this::addTester); } - private boolean applyTesters(RestOperationTypeEnum theOperation, RequestDetails theRequestDetails, IIdType theInputResourceId, IBaseResource theInputResource, IBaseResource theOutputResource) { + private boolean applyTesters(RestOperationTypeEnum theOperation, RequestDetails theRequestDetails, IIdType theInputResourceId, IBaseResource theInputResource, IBaseResource theOutputResource, IRuleApplier theRuleApplier) { assert !(theInputResource != null && theOutputResource != null); boolean retVal = true; if (theOutputResource == null) { + IAuthRuleTester.RuleTestRequest inputRequest = new IAuthRuleTester.RuleTestRequest(myMode, theOperation, theRequestDetails, theInputResourceId, theInputResource, theRuleApplier); + + for (IAuthRuleTester next : getTesters()) { - if (!next.matches(theOperation, theRequestDetails, theInputResourceId, theInputResource)) { + if (!next.matches(inputRequest)) { retVal = false; break; } } } else { + IAuthRuleTester.RuleTestRequest outputRequest = new IAuthRuleTester.RuleTestRequest(myMode, theOperation, theRequestDetails, theOutputResource.getIdElement(), theOutputResource, theRuleApplier); for (IAuthRuleTester next : getTesters()) { - if (!next.matchesOutput(theOperation, theRequestDetails, theOutputResource)) { + if (!next.matchesOutput(outputRequest)) { retVal = false; break; } @@ -98,8 +101,8 @@ abstract class BaseRule implements IAuthRule { return Collections.unmodifiableList(myTesters); } - Verdict newVerdict(RestOperationTypeEnum theOperation, RequestDetails theRequestDetails, IBaseResource theInputResource, IIdType theInputResourceId, IBaseResource theOutputResource) { - if (!applyTesters(theOperation, theRequestDetails, theInputResourceId, theInputResource, theOutputResource)) { + Verdict newVerdict(RestOperationTypeEnum theOperation, RequestDetails theRequestDetails, IBaseResource theInputResource, IIdType theInputResourceId, IBaseResource theOutputResource, IRuleApplier theRuleApplier) { + if (!applyTesters(theOperation, theRequestDetails, theInputResourceId, theInputResource, theOutputResource, theRuleApplier)) { return null; } return new Verdict(myMode, this); diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/FhirQueryRuleTester.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/FhirQueryRuleTester.java new file mode 100644 index 00000000000..ca2f615788e --- /dev/null +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/FhirQueryRuleTester.java @@ -0,0 +1,42 @@ +package ca.uhn.fhir.rest.server.interceptor.auth; + +public class FhirQueryRuleTester implements IAuthRuleTester { + private final String myType; + private final String myFilter; + + public FhirQueryRuleTester(String theType, String theFilter) { + myType = theType; + myFilter = theFilter; + } + + @Override + public boolean matches(RuleTestRequest theRuleTestRequest) { + // wipmb placeholder until we get to writes + return true; + } + + @Override + public boolean matchesOutput(RuleTestRequest theRuleTestRequest) { + + // look for a matcher + IAuthorizationSearchParamMatcher matcher = theRuleTestRequest.ruleApplier.getSearchParamMatcher(); + if (matcher == null) { + return false; + } + + // wipmb myType, or target type? Is this just query filter, or do we bring * into it? + IAuthorizationSearchParamMatcher.MatchResult mr = matcher.match(myType + "?" + myFilter, theRuleTestRequest.resource); + + switch (mr.getMatch()) { + case MATCH: + return true; + case UNSUPPORTED: + theRuleTestRequest.ruleApplier.getTroubleshootingLog().warn("Unsupported matcher expression {}: {}.", myFilter, mr.getUnsupportedReason()); + // unsupported doesn't match unless this is a deny request, and we need to be safe! + return (theRuleTestRequest.mode == PolicyEnum.DENY); + case NO_MATCH: + default: + return false; + } + } +} diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/IAuthRuleTester.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/IAuthRuleTester.java index a2f60e0a96c..17f28e1bad7 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/IAuthRuleTester.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/IAuthRuleTester.java @@ -22,9 +22,13 @@ package ca.uhn.fhir.rest.server.interceptor.auth; import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.server.RequestDetails; +import org.apache.commons.lang3.Validate; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IIdType; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + /** * Allows user-supplied logic for authorization rules. *
@@ -34,6 +38,44 @@ import org.hl7.fhir.instance.model.api.IIdType;
* @since 3.4.0
*/
public interface IAuthRuleTester {
+ /**
+ * A request object to make this easier to extend.
+ */
+ class RuleTestRequest {
+ // fake record pattern
+ /** the mode of the calling rule context */
+ @Nonnull public final PolicyEnum mode;
+ /**
+ * The FHIR operation being performed.
+ * Note that this is not necessarily the same as the value obtained from invoking
+ * {@link RequestDetails#getRestOperationType()} on {@literal requestDetails}
+ * because multiple operations can be nested within
+ * an HTTP request using FHIR transaction and batch operations
+ */
+ @Nonnull public final RestOperationTypeEnum operation;
+ @Nonnull public final RequestDetails requestDetails;
+ @Nullable public final IIdType resourceId;
+ @Nullable public final IBaseResource resource;
+ /** supplier for support services */
+ @Nonnull public final IRuleApplier ruleApplier;
+
+ public RuleTestRequest(PolicyEnum theMode, @Nonnull RestOperationTypeEnum theOperation, @Nonnull RequestDetails theRequestDetails, @Nullable IIdType theResourceId, @Nullable IBaseResource theResource, @Nonnull IRuleApplier theRuleApplier) {
+ Validate.notNull(theMode);
+ Validate.notNull(theOperation);
+ Validate.notNull(theRequestDetails);
+ Validate.notNull(theRuleApplier);
+ mode = theMode;
+ operation = theOperation;
+ requestDetails = theRequestDetails;
+ resource = theResource;
+ if (theResourceId == null && resource != null) {
+ resourceId = resource.getIdElement();
+ } else {
+ resourceId = theResourceId;
+ }
+ ruleApplier = theRuleApplier;
+ }
+ }
/**
* Allows user-supplied logic for authorization rules.
@@ -41,11 +83,19 @@ public interface IAuthRuleTester {
* THIS IS AN EXPERIMENTAL API! Feedback is welcome, and this API
* may change.
*
- * @param theOperation The FHIR operation being performed - Note that this is not necessarily the same as the value obtained from invoking
- * {@link RequestDetails#getRestOperationType()} on {@literal theRequestDetails} because multiple operations can be nested within
- * an HTTP request using FHIR transaction and batch operations
- * @since 3.4.0
+ * @param theRequest The details to evaluate
+ * @since 6.1.0
*/
+ default boolean matches(RuleTestRequest theRequest) {
+ return this.matches(theRequest.operation, theRequest.requestDetails, theRequest.resourceId, theRequest.resource);
+ }
+
+
+ /**
+ * DO NOT IMPLEMENT - Old api. {@link #matches(RuleTestRequest)} instead.
+ * @deprecated
+ */
+ @Deprecated(since = "6.1.0")
default boolean matches(RestOperationTypeEnum theOperation, RequestDetails theRequestDetails, IIdType theInputResourceId, IBaseResource theInputResource) {
return true;
}
@@ -56,11 +106,18 @@ public interface IAuthRuleTester {
* THIS IS AN EXPERIMENTAL API! Feedback is welcome, and this API
* may change.
*
- * @param theOperation The FHIR operation being performed - Note that this is not necessarily the same as the value obtained from invoking
- * {@link RequestDetails#getRestOperationType()} on {@literal theRequestDetails} because multiple operations can be nested within
- * an HTTP request using FHIR transaction and batch operations
- * @since 5.0.0
+ * @param theRequest The details to evaluate
+ * @since 6.1.0
*/
+ default boolean matchesOutput(RuleTestRequest theRequest) {
+ return this.matchesOutput(theRequest.operation, theRequest.requestDetails, theRequest.resource);
+ }
+
+ /**
+ * DO NOT IMPLEMENT - Old api. {@link #matches(RuleTestRequest)} instead.
+ * @deprecated
+ */
+ @Deprecated(since = "6.1.0")
default boolean matchesOutput(RestOperationTypeEnum theOperation, RequestDetails theRequestDetails, IBaseResource theOutputResource) {
return true;
}
diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/IAuthorizationSearchParamMatcher.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/IAuthorizationSearchParamMatcher.java
index ca3e4da5c9b..d126ac8f071 100644
--- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/IAuthorizationSearchParamMatcher.java
+++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/IAuthorizationSearchParamMatcher.java
@@ -23,36 +23,42 @@ package ca.uhn.fhir.rest.server.interceptor.auth;
import org.hl7.fhir.instance.model.api.IBaseResource;
import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
/**
- * wipjv Ken do we like this name, or this package?
+ * Adapt the InMemoryMatcher to support authorization filters in {@link FhirQueryRuleImpl}.
*/
public interface IAuthorizationSearchParamMatcher {
MatchResult match(String theCriteria, IBaseResource theResource);
+ /**
+ * Match outcomes.
+ */
enum Match {
MATCH,
NO_MATCH,
+ /** Used for contexts without matcher infrastructure like hybrid providers */
UNSUPPORTED
}
- public static class MatchResult {
- private final Match myMatch;
- private final String myUnsupportedReason;
+ class MatchResult {
+ // wipmb consider a record pattern - public and drop the accessors.
+ @Nonnull private final Match myMatch;
+ @Nullable private final String myUnsupportedReason;
- public static MatchResult makeMatched() {
+ public static MatchResult buildMatched() {
return new MatchResult(Match.MATCH, null);
}
- public static MatchResult makeUnmatched() {
+ public static MatchResult buildUnmatched() {
return new MatchResult(Match.NO_MATCH, null);
}
- public static MatchResult makeUnsupported(@Nonnull String theReason) {
+ public static MatchResult buildUnsupported(@Nonnull String theReason) {
return new MatchResult(Match.UNSUPPORTED, theReason);
}
- public MatchResult(Match myMatch, String myUnsupportedReason) {
+ private MatchResult(Match myMatch, String myUnsupportedReason) {
this.myMatch = myMatch;
this.myUnsupportedReason = myUnsupportedReason;
}
diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/OperationRule.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/OperationRule.java
index b08446aa530..2a4098aff96 100644
--- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/OperationRule.java
+++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/OperationRule.java
@@ -199,7 +199,7 @@ class OperationRule extends BaseRule implements IAuthRule {
return null;
}
- return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource);
+ return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource, theRuleApplier);
}
/**
diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBuilder.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBuilder.java
index 584e5b23402..9e23de12b58 100644
--- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBuilder.java
+++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBuilder.java
@@ -583,7 +583,6 @@ public class RuleBuilder implements IAuthRuleBuilder {
@Override
public IAuthRuleFinished inCompartmentWithFilter(String theCompartmentName, IIdType theIdElement, String theFilter) {
- // wipjv (resolved?) implemented
Validate.notBlank(theCompartmentName, "theCompartmentName must not be null");
Validate.notNull(theIdElement, "theOwner must not be null");
validateOwner(theIdElement);
diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBulkExportImpl.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBulkExportImpl.java
index 092b066e951..9effd068e7f 100644
--- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBulkExportImpl.java
+++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBulkExportImpl.java
@@ -72,14 +72,14 @@ public class RuleBulkExportImpl extends BaseRule {
}
if (myWantAnyStyle || myWantExportStyle == BulkDataExportOptions.ExportStyle.SYSTEM) {
- return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource);
+ return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource, theRuleApplier);
}
if (isNotBlank(myGroupId) && options.getGroupId() != null) {
String expectedGroupId = new IdDt(myGroupId).toUnqualifiedVersionless().getValue();
String actualGroupId = options.getGroupId().toUnqualifiedVersionless().getValue();
if (Objects.equals(expectedGroupId, actualGroupId)) {
- return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource);
+ return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource, theRuleApplier);
}
}
return null;
diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleImplConditional.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleImplConditional.java
index ccb1b33219f..86cb3f0974c 100644
--- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleImplConditional.java
+++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleImplConditional.java
@@ -72,7 +72,7 @@ public class RuleImplConditional extends BaseRule implements IAuthRule {
break;
}
- return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource);
+ return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource, theRuleApplier);
}
return null;
diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleImplOp.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleImplOp.java
index 374018c407d..11da0e3a4c7 100644
--- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleImplOp.java
+++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleImplOp.java
@@ -115,12 +115,12 @@ class RuleImplOp extends BaseRule /* implements IAuthRule */ {
case SEARCH_SYSTEM:
case HISTORY_SYSTEM:
if (theFlags.contains(AuthorizationFlagsEnum.DO_NOT_PROACTIVELY_BLOCK_COMPARTMENT_READ_ACCESS)) {
- return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource);
+ return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource, theRuleApplier);
}
break;
case SEARCH_TYPE:
if (theFlags.contains(AuthorizationFlagsEnum.DO_NOT_PROACTIVELY_BLOCK_COMPARTMENT_READ_ACCESS)) {
- return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource);
+ return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource, theRuleApplier);
}
target.resourceType = theRequestDetails.getResourceName();
target.setSearchParams(theRequestDetails);
@@ -135,18 +135,18 @@ class RuleImplOp extends BaseRule /* implements IAuthRule */ {
break;
case HISTORY_TYPE:
if (theFlags.contains(AuthorizationFlagsEnum.DO_NOT_PROACTIVELY_BLOCK_COMPARTMENT_READ_ACCESS)) {
- return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource);
+ return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource, theRuleApplier);
}
target.resourceType = theRequestDetails.getResourceName();
break;
case HISTORY_INSTANCE:
if (theFlags.contains(AuthorizationFlagsEnum.DO_NOT_PROACTIVELY_BLOCK_COMPARTMENT_READ_ACCESS)) {
- return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource);
+ return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource, theRuleApplier);
}
target.resourceIds = Collections.singleton(theInputResourceId);
break;
case GET_PAGE:
- return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource);
+ return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource, theRuleApplier);
// None of the following are checked on the way in
case ADD_TAGS:
@@ -222,7 +222,7 @@ class RuleImplOp extends BaseRule /* implements IAuthRule */ {
case DELETE:
if (theOperation == RestOperationTypeEnum.DELETE) {
if (thePointcut == Pointcut.STORAGE_PRE_DELETE_EXPUNGE && myAppliesToDeleteExpunge) {
- return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource);
+ return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource, theRuleApplier);
}
if (myAppliesToDeleteCascade != (thePointcut == Pointcut.STORAGE_CASCADE_DELETE)) {
return null;
@@ -233,10 +233,10 @@ class RuleImplOp extends BaseRule /* implements IAuthRule */ {
if (theInputResourceId.hasIdPart() == false) {
// This is a conditional DELETE, so we'll authorize it using STORAGE events instead
// so just let it through for now..
- return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource);
+ return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource, theRuleApplier);
}
if (theInputResource == null && myClassifierCompartmentOwners != null && myClassifierCompartmentOwners.size() > 0) {
- return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource);
+ return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource, theRuleApplier);
}
target.resource = theInputResource;
@@ -246,14 +246,14 @@ class RuleImplOp extends BaseRule /* implements IAuthRule */ {
}
break;
case GRAPHQL:
- return applyRuleToGraphQl(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource, thePointcut);
+ return applyRuleToGraphQl(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource, thePointcut, theRuleApplier);
case TRANSACTION:
return applyRuleToTransaction(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource, theRuleApplier, thePointcut, ctx);
case ALL:
- return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource);
+ return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource, theRuleApplier);
case METADATA:
if (theOperation == RestOperationTypeEnum.METADATA) {
- return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource);
+ return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource, theRuleApplier);
}
return null;
default:
@@ -263,11 +263,11 @@ class RuleImplOp extends BaseRule /* implements IAuthRule */ {
switch (myAppliesTo) {
case INSTANCES:
- return applyRuleToInstances(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource, target);
+ return applyRuleToInstances(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource, target, theRuleApplier);
case ALL_RESOURCES:
if (target.resourceType != null) {
if (myClassifierType == ClassifierTypeEnum.ANY_ID) {
- return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource);
+ return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource, theRuleApplier);
}
}
break;
@@ -295,7 +295,7 @@ class RuleImplOp extends BaseRule /* implements IAuthRule */ {
return null;
}
if (myClassifierType == ClassifierTypeEnum.ANY_ID) {
- return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource);
+ return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource, theRuleApplier);
} else if (myClassifierType == ClassifierTypeEnum.IN_COMPARTMENT) {
// ok we'll check below
}
@@ -320,16 +320,16 @@ class RuleImplOp extends BaseRule /* implements IAuthRule */ {
case ANY_ID:
break;
case IN_COMPARTMENT:
- return applyRuleToCompartment(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource, theFlags, theFhirContext, theRuleTarget);
+ return applyRuleToCompartment(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource, theFlags, theFhirContext, theRuleTarget, theRuleApplier);
default:
throw new IllegalStateException(Msg.code(337) + "Unable to apply security to event of applies to type " + myAppliesTo);
}
- return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource);
+ return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource, theRuleApplier);
}
@Nullable
- private Verdict applyRuleToGraphQl(RestOperationTypeEnum theOperation, RequestDetails theRequestDetails, IBaseResource theInputResource, IIdType theInputResourceId, IBaseResource theOutputResource, Pointcut thePointcut) {
+ private Verdict applyRuleToGraphQl(RestOperationTypeEnum theOperation, RequestDetails theRequestDetails, IBaseResource theInputResource, IIdType theInputResourceId, IBaseResource theOutputResource, Pointcut thePointcut, IRuleApplier theRuleApplier) {
if (theOperation == RestOperationTypeEnum.GRAPHQL_REQUEST) {
// Make sure that the requestor actually has sufficient access to see the given resource
@@ -337,14 +337,14 @@ class RuleImplOp extends BaseRule /* implements IAuthRule */ {
return null;
}
- return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource);
+ return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource, theRuleApplier);
} else {
return null;
}
}
@Nullable
- private Verdict applyRuleToCompartment(RestOperationTypeEnum theOperation, RequestDetails theRequestDetails, IBaseResource theInputResource, IIdType theInputResourceId, IBaseResource theOutputResource, Set