From 52bdc2693c29969e7e61f28e7610c084b0a67b0f Mon Sep 17 00:00:00 2001 From: volodymyr-korzh <132366313+volodymyr-korzh@users.noreply.github.com> Date: Mon, 23 Oct 2023 14:26:25 -0600 Subject: [PATCH] Transaction with conditional update fails if SearchNarrowingInterceptor is registered and Enabled Partitioning (#5389) * Transaction with conditional update fails if SearchNarrowingInterceptor is registered and Enabled Partitioning - Implementation --- ...s-registered-and-partitioning-enabled.yaml | 6 +++ .../provider/r4/MultitenantServerR4Test.java | 54 +++++++++++++++++++ .../uhn/fhir/rest/server/RestfulServer.java | 18 +++++-- .../tenant/ITenantIdentificationStrategy.java | 11 +++- .../UrlBaseTenantIdentificationStrategy.java | 8 +++ .../rest/server/util/ServletRequestUtil.java | 1 + 6 files changed, 92 insertions(+), 6 deletions(-) create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_10_0/5388-fhir-transaction-fails-if-searchnarrowinginterceptor-is-registered-and-partitioning-enabled.yaml diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_10_0/5388-fhir-transaction-fails-if-searchnarrowinginterceptor-is-registered-and-partitioning-enabled.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_10_0/5388-fhir-transaction-fails-if-searchnarrowinginterceptor-is-registered-and-partitioning-enabled.yaml new file mode 100644 index 00000000000..dcfc89bcc74 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_10_0/5388-fhir-transaction-fails-if-searchnarrowinginterceptor-is-registered-and-partitioning-enabled.yaml @@ -0,0 +1,6 @@ +--- +type: fix +issue: 5388 +title: "Previously, with partitioning enabled and `UrlBaseTenantIdentificationStrategy` used, registering +`SearchNarrowingInterceptor` would cause to incorrect resolution of `entry.request.url` parameter during +transaction bundle processing. This has been fixed." diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/MultitenantServerR4Test.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/MultitenantServerR4Test.java index 5c5e356a283..139f4df1e5a 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/MultitenantServerR4Test.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/MultitenantServerR4Test.java @@ -23,6 +23,7 @@ import ca.uhn.fhir.rest.server.RestfulServer; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; +import ca.uhn.fhir.rest.server.interceptor.auth.SearchNarrowingInterceptor; import ca.uhn.fhir.rest.server.provider.ProviderConstants; import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; import ca.uhn.fhir.test.utilities.ITestDataBuilder; @@ -40,11 +41,14 @@ import org.hl7.fhir.r4.model.Condition; import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.Organization; import org.hl7.fhir.r4.model.Patient; +import org.hl7.fhir.r4.model.Resource; import org.hl7.fhir.r4.model.StringType; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Spy; @@ -65,6 +69,7 @@ import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.hasSize; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; @@ -424,6 +429,55 @@ public class MultitenantServerR4Test extends BaseMultitenantResourceProviderR4Te } + @Test + public void testTransactionPut_withSearchNarrowingInterceptor_createsPatient() { + // setup + IBaseResource patientA = buildPatient(withTenant(TENANT_B), withActiveTrue(), withId("1234a"), + withFamily("Family"), withGiven("Given")); + + Bundle transactioBundle = new Bundle(); + transactioBundle.setType(Bundle.BundleType.TRANSACTION); + transactioBundle.addEntry() + .setFullUrl("http://localhost:8000/TENANT-A/Patient/1234a") + .setResource((Resource) patientA) + .getRequest().setUrl("Patient/1234a").setMethod(Bundle.HTTPVerb.PUT); + + myServer.registerInterceptor(new SearchNarrowingInterceptor()); + + // execute + myClient.transaction().withBundle(transactioBundle).execute(); + + // verify - read back using DAO + SystemRequestDetails requestDetails = new SystemRequestDetails(); + requestDetails.setTenantId(TENANT_B); + Patient patient1 = myPatientDao.read(new IdType("Patient/1234a"), requestDetails); + assertEquals("Family", patient1.getName().get(0).getFamily()); + } + + @ParameterizedTest + @ValueSource(strings = {"Patient/1234a", "TENANT-B/Patient/1234a"}) + public void testTransactionGet_withSearchNarrowingInterceptor_retrievesPatient(String theEntryUrl) { + // setup + createPatient(withTenant(TENANT_B), withActiveTrue(), withId("1234a"), + withFamily("Family"), withGiven("Given")); + + Bundle transactioBundle = new Bundle(); + transactioBundle.setType(Bundle.BundleType.TRANSACTION); + transactioBundle.addEntry() + .getRequest().setUrl(theEntryUrl).setMethod(Bundle.HTTPVerb.GET); + + myServer.registerInterceptor(new SearchNarrowingInterceptor()); + + // execute + Bundle result = myClient.transaction().withBundle(transactioBundle).execute(); + + // verify + assertEquals(1, result.getEntry().size()); + Patient retrievedPatient = (Patient) result.getEntry().get(0).getResource(); + assertNotNull(retrievedPatient); + assertEquals("Family", retrievedPatient.getName().get(0).getFamily()); + } + @Test public void testDirectDaoAccess_PartitionInRequestDetails_Create() { diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java index 02dbd0d5ccd..550a9d28fd3 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java @@ -1598,9 +1598,16 @@ public class RestfulServer extends HttpServlet implements IRestfulServer