When Client Id Strategy is set to NOT_ALLOWED, permit system requests to create resources (#2827)

* resolved 2826

* fix regression
This commit is contained in:
Ken Stevens 2021-07-23 19:10:19 -04:00 committed by GitHub
parent 92ec113775
commit 6bbb403fd1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 114 additions and 18 deletions

View File

@ -0,0 +1,5 @@
---
type: fix
issue: 2826
title: "When Client Id Strategy is set to NOT_ALLOWED, permit system requests to create resources, e.g. SearchParameter
and Subscription resources required by the system."

View File

@ -47,6 +47,7 @@ import ca.uhn.fhir.jpa.model.entity.TagTypeEnum;
import ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails;
import ca.uhn.fhir.jpa.model.util.JpaConstants;
import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
import ca.uhn.fhir.jpa.patch.FhirPatch;
import ca.uhn.fhir.jpa.patch.JsonPatchUtils;
import ca.uhn.fhir.jpa.patch.XmlPatchUtils;
@ -126,7 +127,6 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
import org.springframework.transaction.support.TransactionTemplate;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.PostConstruct;
import javax.persistence.NoResultException;
import javax.persistence.TypedQuery;
@ -228,7 +228,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
if (isNotBlank(theResource.getIdElement().getIdPart())) {
if (getContext().getVersion().getVersion().isOlderThan(FhirVersionEnum.DSTU3)) {
String message = getContext().getLocalizer().getMessageSanitized(BaseHapiFhirResourceDao.class, "failedToCreateWithClientAssignedId", theResource.getIdElement().getIdPart());
String message = getMessageSanitized("failedToCreateWithClientAssignedId", theResource.getIdElement().getIdPart());
throw new InvalidRequestException(message, createErrorOperationOutcome(message, "processing"));
} else {
// As of DSTU3, ID and version in the body should be ignored for a create/update
@ -305,21 +305,9 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
createForcedIdIfNeeded(entity, theResource.getIdElement(), true);
serverAssignedId = true;
} else {
switch (getConfig().getResourceClientIdStrategy()) {
case NOT_ALLOWED:
throw new ResourceNotFoundException(
getContext().getLocalizer().getMessageSanitized(BaseHapiFhirResourceDao.class, "failedToCreateWithClientAssignedIdNotAllowed", theResource.getIdElement().getIdPart()));
case ALPHANUMERIC:
if (theResource.getIdElement().isIdPartValidLong()) {
throw new InvalidRequestException(
getContext().getLocalizer().getMessageSanitized(BaseHapiFhirResourceDao.class, "failedToCreateWithClientAssignedNumericId", theResource.getIdElement().getIdPart()));
}
createForcedIdIfNeeded(entity, theResource.getIdElement(), false);
break;
case ANY:
createForcedIdIfNeeded(entity, theResource.getIdElement(), true);
break;
}
validateResourceIdCreation(theResource, theRequest);
boolean createForPureNumericIds = getConfig().getResourceClientIdStrategy() != DaoConfig.ClientIdStrategyEnum.ALPHANUMERIC;
createForcedIdIfNeeded(entity, theResource.getIdElement(), createForPureNumericIds);
serverAssignedId = false;
}
} else {
@ -407,6 +395,32 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
return outcome;
}
void validateResourceIdCreation(T theResource, RequestDetails theRequest) {
DaoConfig.ClientIdStrategyEnum strategy = getConfig().getResourceClientIdStrategy();
if (strategy == DaoConfig.ClientIdStrategyEnum.NOT_ALLOWED) {
if (!isSystemRequest(theRequest)) {
throw new ResourceNotFoundException(
getMessageSanitized("failedToCreateWithClientAssignedIdNotAllowed", theResource.getIdElement().getIdPart()));
}
}
if (strategy == DaoConfig.ClientIdStrategyEnum.ALPHANUMERIC) {
if (theResource.getIdElement().isIdPartValidLong()) {
throw new InvalidRequestException(
getMessageSanitized("failedToCreateWithClientAssignedNumericId", theResource.getIdElement().getIdPart()));
}
}
}
protected String getMessageSanitized(String theKey, String theIdPart) {
return getContext().getLocalizer().getMessageSanitized(BaseHapiFhirResourceDao.class, theKey, theIdPart);
}
private boolean isSystemRequest(RequestDetails theRequest) {
return theRequest instanceof SystemRequestDetails;
}
private IInstanceValidatorModule getInstanceValidator() {
return myInstanceValidator;
}
@ -632,7 +646,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
IBaseOperationOutcome oo;
if (deletedResources.isEmpty()) {
oo = OperationOutcomeUtil.newInstance(getContext());
String message = getContext().getLocalizer().getMessageSanitized(BaseHapiFhirResourceDao.class, "unableToDeleteNotFound", theUrl);
String message = getMessageSanitized("unableToDeleteNotFound", theUrl);
String severity = "warning";
String code = "not-found";
OperationOutcomeUtil.addIssue(getContext(), oo, severity, message, null, code);

View File

@ -0,0 +1,77 @@
package ca.uhn.fhir.jpa.dao;
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import org.hl7.fhir.r4.model.Patient;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
class BaseHapiFhirResourceDaoTest {
TestResourceDao mySvc = new TestResourceDao();
@Test
public void validateResourceIdCreation_asSystem() {
Patient patient = new Patient();
RequestDetails sysRequest = new SystemRequestDetails();
mySvc.getConfig().setResourceClientIdStrategy(DaoConfig.ClientIdStrategyEnum.NOT_ALLOWED);
mySvc.validateResourceIdCreation(patient, sysRequest);
// no exception is thrown
}
@Test
public void validateResourceIdCreation_asUser() {
Patient patient = new Patient();
RequestDetails sysRequest = new ServletRequestDetails();
mySvc.getConfig().setResourceClientIdStrategy(DaoConfig.ClientIdStrategyEnum.NOT_ALLOWED);
try {
mySvc.validateResourceIdCreation(patient, sysRequest);
fail();
} catch (ResourceNotFoundException e) {
assertEquals("failedToCreateWithClientAssignedIdNotAllowed", e.getMessage());
}
}
@Test
public void validateResourceIdCreationAlpha_withNumber() {
Patient patient = new Patient();
patient.setId("2401");
RequestDetails sysRequest = new ServletRequestDetails();
mySvc.getConfig().setResourceClientIdStrategy(DaoConfig.ClientIdStrategyEnum.ALPHANUMERIC);
try {
mySvc.validateResourceIdCreation(patient, sysRequest);
fail();
} catch (InvalidRequestException e) {
assertEquals("failedToCreateWithClientAssignedNumericId", e.getMessage());
}
}
@Test
public void validateResourceIdCreationAlpha_withAlpha() {
Patient patient = new Patient();
patient.setId("P2401");
RequestDetails sysRequest = new ServletRequestDetails();
mySvc.getConfig().setResourceClientIdStrategy(DaoConfig.ClientIdStrategyEnum.ALPHANUMERIC);
mySvc.validateResourceIdCreation(patient, sysRequest);
// no exception is thrown
}
static class TestResourceDao extends BaseHapiFhirResourceDao<Patient> {
private final DaoConfig myDaoConfig = new DaoConfig();
@Override
public DaoConfig getConfig() {
return myDaoConfig;
}
@Override
protected String getMessageSanitized(String theKey, String theIdPart) {
return theKey;
}
}
}