hapi-fhir
hapi-fhir copied to clipboard
SearchNarrowingInterceptor mixes up patients and practitioners for Appointment
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.