Handle invalid resourceType when performing FHIR search with non-chained reference (#5674)

* Throw exception when resourceType of parameter value is invalid when performing FHIR search with non-chained reference

* Fix changelog issue id and spotless warning

* Cleanup unnecessary test

* Validate resourceType only when using relative reference

* Fix test for search using _type parameter
This commit is contained in:
Martha Mitran 2024-02-08 08:08:13 -08:00 committed by GitHub
parent 993cfcce99
commit 43f1e4b2dd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 59 additions and 9 deletions

View File

@ -0,0 +1,6 @@
---
type: fix
issue: 5672
title: "Previously, when performing a FHIR search using a non-chained relative reference (returns entire resource) with
a server assigned id, it ignores the invalid resourceType in the parameter value and proceeds with the id based lookup. e.g.
GET `/MedicationAdministration?context=abc/1352` returns `Encounter/1352`. This has been fixed."

View File

@ -70,6 +70,7 @@ import com.healthmarketscience.sqlbuilder.UnaryCondition;
import com.healthmarketscience.sqlbuilder.dbspec.basic.DbColumn;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.slf4j.Logger;
@ -204,6 +205,7 @@ public class ResourceLinkPredicateBuilder extends BaseJoiningPredicateBuilder im
targetQualifiedUrls.add(dt.getValue());
}
} else {
validateResourceTypeInReferenceParam(ref.getResourceType());
targetIds.add(dt);
}
@ -256,6 +258,18 @@ public class ResourceLinkPredicateBuilder extends BaseJoiningPredicateBuilder im
}
}
private void validateResourceTypeInReferenceParam(final String theResourceType) {
if (StringUtils.isEmpty(theResourceType)) {
return;
}
try {
getFhirContext().getResourceDefinition(theResourceType);
} catch (DataFormatException e) {
throw newInvalidResourceTypeException(theResourceType);
}
}
private Condition createPredicateReference(
boolean theInverse,
List<String> thePathsToMatch,
@ -362,11 +376,7 @@ public class ResourceLinkPredicateBuilder extends BaseJoiningPredicateBuilder im
String typeValue = theReferenceParam.getValue();
try {
getFhirContext().getResourceDefinition(typeValue).getImplementingClass();
} catch (DataFormatException e) {
throw newInvalidResourceTypeException(typeValue);
}
validateResourceTypeInReferenceParam(typeValue);
if (!resourceTypes.contains(typeValue)) {
throw newInvalidTargetTypeForChainException(theResourceName, theParamName, typeValue);
}
@ -705,7 +715,7 @@ public class ResourceLinkPredicateBuilder extends BaseJoiningPredicateBuilder im
.getLocalizer()
.getMessage(
ResourceLinkPredicateBuilder.class, "invalidTargetTypeForChain", theTypeValue, searchParamName);
return new InvalidRequestException(msg);
return new InvalidRequestException(Msg.code(2495) + msg);
}
@Nonnull

View File

@ -23,7 +23,6 @@ import ca.uhn.fhir.jpa.model.entity.ResourceLink;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.model.search.StorageProcessingMessage;
import ca.uhn.fhir.jpa.model.util.UcumServiceUtil;
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap.EverythingModeEnum;
@ -36,6 +35,7 @@ import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
import ca.uhn.fhir.parser.StrictErrorHandler;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
import ca.uhn.fhir.rest.param.CompositeParam;
import ca.uhn.fhir.rest.param.DateParam;
import ca.uhn.fhir.rest.param.DateRangeParam;
@ -60,6 +60,7 @@ import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
import ca.uhn.fhir.util.HapiExtensions;
import com.google.common.collect.Lists;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
@ -151,7 +152,6 @@ import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
@ -658,7 +658,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
myEncounterDao.search(map);
fail();
} catch (InvalidRequestException e) {
assertEquals("Resource type \"Organization\" is not a valid target type for reference search parameter: Encounter:subject", e.getMessage());
assertEquals(Msg.code(2495) + "Resource type \"Organization\" is not a valid target type for reference search parameter: Encounter:subject", e.getMessage());
}
map = new SearchParameterMap();
@ -3549,7 +3549,41 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
map.add(Task.SP_REQUESTER, new ReferenceParam(oid1.getValue()));
ids = toUnqualifiedVersionlessIds(myTaskDao.search(map));
assertThat(ids, contains(tid1)); // NOT tid2
}
@Test
public void testSearchWithValidTypedResourceReference_returnsCorrectly() {
// setup
IIdType encounterId = createEncounter(withIdentifier("http://example", "someValue"));
MedicationAdministration ma = new MedicationAdministration()
.setContext(new Reference(encounterId))
.setEffective(new DateTimeType());
IIdType medicationAdministrationId = myMedicationAdministrationDao.create(ma, mySrd).getId();
// execute
ReferenceParam referenceParam = new ReferenceParam(encounterId.getResourceType(), null, encounterId.getIdPart());
SearchParameterMap map = new SearchParameterMap().add(MedicationAdministration.SP_CONTEXT, referenceParam);
// verify
List<IIdType> ids = toUnqualifiedVersionlessIds(myMedicationAdministrationDao.search(map, mySrd));
assertEquals(1, ids.size());
assertThat(ids, contains(medicationAdministrationId.toUnqualifiedVersionless()));
}
@Test
public void testSearchWithInvalidTypedResourceReference_throwsUnsupportedResourceType() {
// execute
try {
ReferenceParam referenceParam = new ReferenceParam("abc", null, "123");
SearchParameterMap map = new SearchParameterMap().setLoadSynchronous(true).add(MedicationAdministration.SP_CONTEXT, referenceParam);
// verify
myMedicationAdministrationDao.search(map, mySrd);
fail();
} catch (InvalidRequestException e) {
assertEquals(Msg.code(1250) + "Invalid/unsupported resource type: \"abc\"", e.getMessage());
}
}
@Test