hapi-fhir icon indicating copy to clipboard operation
hapi-fhir copied to clipboard

SearchNarrowingInterceptor mixes up patients and practitioners for Appointment

Open josepedrocorreia opened this issue 1 year ago • 0 comments

Description SearchNarrowingInterceptor seems to be mixing up patient and practitioner parameters for the purpose of adding a compartment.

For example, say that I implemented an interceptor that always adds a compartment with name Practitioner/123 to the search request. When I make a simple search, namely to /Appointment, the request that eventually gets executed is the equivalent to /Appointment?practitioner=Practitioner/123, as expected. However, if I parameterize the search to look for a specific patient, e.g. /Appointment?patient=Patient/456, the request results in a 403 error.

The expected behavior is that request /Appointment?patient=Patient/456 gets executed as /Appointment?patient=Patient/456&practitioner=Practitioner/123.

I suspect that this happens because SearchNarrowingInterceptor.findSynonyms reduces both parameters to the base path Appointment.participant.actor, which in turn causes SearchNarrowingInterceptor.selectBestSearchParameterForCompartment to think that the compartment parameter is already added to the request.

To Reproduce To reproduce the behavior, add the following to SearchNarrowingInterceptorTest:

	public static class DummyAppointmentResourceProvider implements IResourceProvider {

		@Override
		public Class<? extends IBaseResource> getResourceType() {
			return Appointment.class;
		}

		@Search()
		public List<Resource> search(
			@OptionalParam(name = "_id") TokenAndListParam theIdParam,
			@OptionalParam(name = Appointment.SP_PATIENT) ReferenceAndListParam thePatientParam,
			@OptionalParam(name = Appointment.SP_PRACTITIONER) ReferenceAndListParam thePerformerParam
		) {
			ourLastHitMethod = "Appointment.search";
			ourLastIdParam = theIdParam;
			ourLastPatientParam = thePatientParam;
			ourLastPerformerParam = thePerformerParam;
			return ourReturn;
		}

	}

	@Test
	public void testNarrowAppointmentsByPractitionerContext_ClientRequestedNoParams() {
		ourNextCompartmentList = new AuthorizedList().addCompartments("Practitioner/123");

		ourClient
			.search()
			.forResource("Appointment")
			.execute();

		assertEquals("Appointment.search", ourLastHitMethod);
		assertNull(ourLastIdParam);
		assertNull(ourLastPatientParam);
		assertThat(toStrings(ourLastPerformerParam), Matchers.contains("Practitioner/123"));
	}

	@Test
	public void testNarrowAppointmentsByPractitionerContext_ClientRequestedPatientParam() {
		ourNextCompartmentList = new AuthorizedList().addCompartments("Practitioner/123");

		ourClient
			.search()
			.forResource("Appointment")
			.where(Appointment.PATIENT.hasId("Patient/456"))
			.execute();

		assertEquals("Appointment.search", ourLastHitMethod);
		assertNull(ourLastIdParam);
		assertThat(toStrings(ourLastPatientParam), Matchers.contains("Patient/456"));
		assertThat(toStrings(ourLastPerformerParam), Matchers.contains("Practitioner/123"));
	}

Additionally, add the new dummy interceptor to the servlet on line 448:

	ourServlet.setResourceProviders(patProvider, obsProv, new DummyAppointmentResourceProvider());

Expected behavior Both tests should pass, but testNarrowAppointmentsByPractitionerContext_ClientRequestedPatientParam throws ForbiddenOperationException: HTTP 403 Forbidden.

Environment

  • HAPI FHIR Version: v5.7.2
  • OS: [e.g. iOS]: Ubuntu

Additional context Although I'm experiencing this problem on version v5.7.2, from looking into the code I would say it probably occurs in the most recent versions as well.

josepedrocorreia avatar Aug 21 '22 18:08 josepedrocorreia