diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_1_0/3749-consent-overreach.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_1_0/3749-consent-overreach.yaml new file mode 100644 index 00000000000..6fecbdbd7b6 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_1_0/3749-consent-overreach.yaml @@ -0,0 +1,4 @@ +--- +type: fix +issue: 3749 +title: "Fixed a regression in 6.0.0 which caused the SearchNarrowingInterceptor to occcasionally be applied to non-search operations." diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/SearchNarrowingInterceptor.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/SearchNarrowingInterceptor.java index bf40287185e..f15689af946 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/SearchNarrowingInterceptor.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/SearchNarrowingInterceptor.java @@ -146,6 +146,11 @@ public class SearchNarrowingInterceptor { // We don't support this operation type yet Validate.isTrue(theRequestDetails.getRestOperationType() != RestOperationTypeEnum.SEARCH_SYSTEM); + //N.B do not add code above this for filtering, this should only ever occur on search. + if (shouldSkipNarrowing(theRequestDetails)) { + return true; + } + AuthorizedList authorizedList = buildAuthorizedList(theRequestDetails); if (authorizedList == null) { return true; @@ -157,9 +162,6 @@ public class SearchNarrowingInterceptor { postFilteringList.addAll(authorizedList.getAllowedCodeInValueSets()); } - if (theRequestDetails.getRestOperationType() != RestOperationTypeEnum.SEARCH_TYPE) { - return true; - } FhirContext ctx = theRequestDetails.getServer().getFhirContext(); RuntimeResourceDefinition resDef = ctx.getResourceDefinition(theRequestDetails.getResourceName()); @@ -186,6 +188,15 @@ public class SearchNarrowingInterceptor { return true; } + + /** + * Skip unless it is a search request or an $everything operation + */ + private boolean shouldSkipNarrowing(RequestDetails theRequestDetails) { + return theRequestDetails.getRestOperationType() != RestOperationTypeEnum.SEARCH_TYPE + && !"$everything".equalsIgnoreCase(theRequestDetails.getOperation()); + } + @Hook(Pointcut.SERVER_INCOMING_REQUEST_PRE_HANDLED) public void hookIncomingRequestPreHandled(ServletRequestDetails theRequestDetails, HttpServletRequest theRequest, HttpServletResponse theResponse) throws AuthenticationException { if (theRequestDetails.getRestOperationType() != RestOperationTypeEnum.TRANSACTION) { diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/interceptor/auth/SearchNarrowingInterceptorTest.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/interceptor/auth/SearchNarrowingInterceptorTest.java index 7b696c803fb..2c5497d1163 100644 --- a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/interceptor/auth/SearchNarrowingInterceptorTest.java +++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/interceptor/auth/SearchNarrowingInterceptorTest.java @@ -9,6 +9,7 @@ import ca.uhn.fhir.rest.annotation.Search; import ca.uhn.fhir.rest.annotation.Transaction; import ca.uhn.fhir.rest.annotation.TransactionParam; import ca.uhn.fhir.rest.api.Constants; +import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.client.api.IGenericClient; import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; @@ -29,6 +30,7 @@ import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Observation; import org.hl7.fhir.r4.model.Patient; +import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.Resource; import org.hl7.fhir.r4.model.ValueSet; import org.junit.jupiter.api.AfterAll; @@ -299,6 +301,31 @@ public class SearchNarrowingInterceptorTest { assertEquals("transaction", ourLastHitMethod); assertEquals("Patient?_id=" + URLEncoder.encode("Patient/123,Patient/456"), ourLastBundleRequest.getUrl()); } + @Test + public void testNarrow_OnlyAppliesToSearches() { + ourNextAuthorizedList = new AuthorizedList().addCompartments("Patient/123"); + + + Observation o = new Observation(); + o.setSubject(new Reference("Patient/456")); + + { + //Create a resource outside of the referenced compartment + Bundle bundle = new Bundle(); + bundle.setType(Bundle.BundleType.TRANSACTION); + bundle.addEntry().getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("Observation"); + myClient.transaction().withBundle(bundle).execute(); + } + + { + Bundle bundle = new Bundle(); + bundle.setType(Bundle.BundleType.TRANSACTION); + bundle.addEntry().getRequest().setMethod(Bundle.HTTPVerb.PUT).setUrl("Observation"); + + //Update a resource outside of the referenced compartment + myClient.transaction().withBundle(bundle).execute(); + } + } @Test public void testNarrowCompartment_PatientByPatientContext_ClientRequestedNoParams() {