Add tests
This commit is contained in:
parent
5309e1cebe
commit
0780b7e472
|
@ -41,12 +41,14 @@ import ca.uhn.fhir.rest.annotation.TransactionParam;
|
|||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||
import ca.uhn.fhir.rest.client.BaseHttpClientInvocation;
|
||||
import ca.uhn.fhir.rest.param.ResourceParameter;
|
||||
import ca.uhn.fhir.rest.param.TransactionParameter;
|
||||
import ca.uhn.fhir.rest.param.TransactionParameter.ParamStyle;
|
||||
import ca.uhn.fhir.rest.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.server.IRestfulServer;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
|
||||
|
||||
public class TransactionMethodBinding extends BaseResourceReturningMethodBinding {
|
||||
|
||||
|
@ -176,6 +178,23 @@ public class TransactionMethodBinding extends BaseResourceReturningMethodBinding
|
|||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void populateActionRequestDetailsForInterceptor(RequestDetails theRequestDetails, ActionRequestDetails theDetails, Object[] theMethodParams) {
|
||||
super.populateActionRequestDetailsForInterceptor(theRequestDetails, theDetails, theMethodParams);
|
||||
|
||||
/*
|
||||
* If the method has no parsed resource parameter, we parse here in order to have something for the interceptor.
|
||||
*/
|
||||
if (myTransactionParamIndex != -1) {
|
||||
theDetails.setResource((IBaseResource) theMethodParams[myTransactionParamIndex]);
|
||||
} else {
|
||||
Class<? extends IBaseResource> resourceType = getContext().getResourceDefinition("Bundle").getImplementingClass();
|
||||
theDetails.setResource(ResourceParameter.parseResourceFromRequest(theRequestDetails, this, resourceType));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static BaseHttpClientInvocation createTransactionInvocation(Bundle theBundle, FhirContext theContext) {
|
||||
return new HttpPostClientInvocation(theContext, theBundle);
|
||||
}
|
||||
|
|
|
@ -23,12 +23,14 @@ package ca.uhn.fhir.rest.server.interceptor.auth;
|
|||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hl7.fhir.instance.model.api.IBaseBundle;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||
import ca.uhn.fhir.rest.method.RequestDetails;
|
||||
import ca.uhn.fhir.util.BundleUtil;
|
||||
import ca.uhn.fhir.util.FhirTerser;
|
||||
|
||||
class Rule implements IAuthRule {
|
||||
|
@ -59,8 +61,13 @@ class Rule implements IAuthRule {
|
|||
case WRITE:
|
||||
appliesTo = theInputResource;
|
||||
break;
|
||||
case BATCH:
|
||||
case TRANSACTION:
|
||||
return myMode;
|
||||
if (requestAppliesToTransaction(ctx, myOp, theInputResource)) {
|
||||
return myMode;
|
||||
} else {
|
||||
return RuleVerdictEnum.NO_DECISION;
|
||||
}
|
||||
case ALLOW_ALL:
|
||||
return RuleVerdictEnum.ALLOW;
|
||||
case DENY_ALL:
|
||||
|
@ -111,6 +118,19 @@ class Rule implements IAuthRule {
|
|||
return myMode;
|
||||
}
|
||||
|
||||
private boolean requestAppliesToTransaction(FhirContext theContext, RuleOpEnum theOp, IBaseResource theInputResource) {
|
||||
IBaseBundle request = (IBaseBundle) theInputResource;
|
||||
String bundleType = BundleUtil.getBundleType(theContext, request);
|
||||
switch (theOp) {
|
||||
case TRANSACTION:
|
||||
return "transaction".equals(bundleType);
|
||||
case BATCH:
|
||||
return "batch".equals(bundleType);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return myName;
|
||||
|
|
|
@ -26,5 +26,6 @@ enum RuleOpEnum {
|
|||
ALLOW_ALL,
|
||||
DENY_ALL,
|
||||
TRANSACTION,
|
||||
METADATA
|
||||
METADATA,
|
||||
BATCH
|
||||
}
|
||||
|
|
|
@ -31,7 +31,6 @@ import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
|||
|
||||
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
|
||||
import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
|
||||
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
|
||||
|
@ -98,4 +97,15 @@ public class BundleUtil {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
public static String getBundleType(FhirContext theContext, IBaseBundle theBundle) {
|
||||
RuntimeResourceDefinition def = theContext.getResourceDefinition(theBundle);
|
||||
BaseRuntimeChildDefinition entryChild = def.getChildByName("type");
|
||||
List<IBase> entries = entryChild.getAccessor().getValues(theBundle);
|
||||
if (entries.size() > 0) {
|
||||
IPrimitiveType<?> typeElement = (IPrimitiveType<?>) entries.get(0);
|
||||
return typeElement.getValueAsString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
|||
|
||||
public class LoadingValidationSupportDstu2 implements IValidationSupport {
|
||||
|
||||
private static FhirContext myCtx = FhirContext.forDstu2Hl7Org();
|
||||
private FhirContext myCtx = FhirContext.forDstu2Hl7Org();
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(LoadingValidationSupportDstu2.class);
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
|||
|
||||
public class LoadingValidationSupportDstu3 implements IValidationSupport {
|
||||
|
||||
private static FhirContext myCtx = FhirContext.forDstu3();
|
||||
private FhirContext myCtx = FhirContext.forDstu3();
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(LoadingValidationSupportDstu3.class);
|
||||
|
||||
|
|
|
@ -31,11 +31,11 @@ import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
|||
@SuppressWarnings("unused")
|
||||
public class FhirResourceDaoDstu1Test extends BaseJpaTest {
|
||||
|
||||
private static AnnotationConfigApplicationContext ourCtx;
|
||||
private static AnnotationConfigApplicationContext ourAppCtx;
|
||||
private static IFhirResourceDao<Device> ourDeviceDao;
|
||||
private static IFhirResourceDao<DiagnosticReport> ourDiagnosticReportDao;
|
||||
private static IFhirResourceDao<Encounter> ourEncounterDao;
|
||||
private static FhirContext ourFhirCtx;
|
||||
private static FhirContext ourCtx;
|
||||
private static IFhirResourceDao<Location> ourLocationDao;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu1Test.class);
|
||||
private static IFhirResourceDao<Observation> ourObservationDao;
|
||||
|
@ -126,21 +126,30 @@ public class FhirResourceDaoDstu1Test extends BaseJpaTest {
|
|||
|
||||
@AfterClass
|
||||
public static void afterClass() {
|
||||
ourCtx.close();
|
||||
ourAppCtx.close();
|
||||
ourAppCtx = null;
|
||||
ourCtx = null;
|
||||
ourDeviceDao = null;
|
||||
ourDiagnosticReportDao = null;
|
||||
ourEncounterDao = null;
|
||||
ourLocationDao = null;
|
||||
ourObservationDao = null;
|
||||
ourOrganizationDao = null;
|
||||
ourPatientDao = null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
ourCtx = new AnnotationConfigApplicationContext(TestDstu1Config.class);
|
||||
ourPatientDao = ourCtx.getBean("myPatientDaoDstu1", IFhirResourceDao.class);
|
||||
ourObservationDao = ourCtx.getBean("myObservationDaoDstu1", IFhirResourceDao.class);
|
||||
ourDiagnosticReportDao = ourCtx.getBean("myDiagnosticReportDaoDstu1", IFhirResourceDao.class);
|
||||
ourDeviceDao = ourCtx.getBean("myDeviceDaoDstu1", IFhirResourceDao.class);
|
||||
ourOrganizationDao = ourCtx.getBean("myOrganizationDaoDstu1", IFhirResourceDao.class);
|
||||
ourLocationDao = ourCtx.getBean("myLocationDaoDstu1", IFhirResourceDao.class);
|
||||
ourEncounterDao = ourCtx.getBean("myEncounterDaoDstu1", IFhirResourceDao.class);
|
||||
ourFhirCtx = ourCtx.getBean(FhirContext.class);
|
||||
ourAppCtx = new AnnotationConfigApplicationContext(TestDstu1Config.class);
|
||||
ourDeviceDao = ourAppCtx.getBean("myDeviceDaoDstu1", IFhirResourceDao.class);
|
||||
ourDiagnosticReportDao = ourAppCtx.getBean("myDiagnosticReportDaoDstu1", IFhirResourceDao.class);
|
||||
ourEncounterDao = ourAppCtx.getBean("myEncounterDaoDstu1", IFhirResourceDao.class);
|
||||
ourLocationDao = ourAppCtx.getBean("myLocationDaoDstu1", IFhirResourceDao.class);
|
||||
ourObservationDao = ourAppCtx.getBean("myObservationDaoDstu1", IFhirResourceDao.class);
|
||||
ourOrganizationDao = ourAppCtx.getBean("myOrganizationDaoDstu1", IFhirResourceDao.class);
|
||||
ourPatientDao = ourAppCtx.getBean("myPatientDaoDstu1", IFhirResourceDao.class);
|
||||
ourCtx = ourAppCtx.getBean(FhirContext.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import static org.junit.Assert.assertEquals;
|
|||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
@ -18,7 +17,6 @@ import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
|||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
|
@ -27,14 +25,9 @@ import org.junit.Test;
|
|||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.dstu2.composite.HumanNameDt;
|
||||
import ca.uhn.fhir.model.dstu2.composite.IdentifierDt;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
import ca.uhn.fhir.rest.annotation.RequiredParam;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.rest.param.DateAndListParam;
|
||||
import ca.uhn.fhir.rest.param.ReferenceParam;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.param.TokenParam;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
|
||||
|
@ -57,7 +50,7 @@ public class SearchWithGenericListDstu2Test {
|
|||
*/
|
||||
@Test
|
||||
public void testSearch() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo");
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo&_pretty=true");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
@ -65,6 +58,7 @@ public class SearchWithGenericListDstu2Test {
|
|||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertEquals("searchByIdentifier", ourLastMethod);
|
||||
assertThat(responseContent, containsString("<family value=\"FAMILY\""));
|
||||
assertThat(responseContent, containsString("<fullUrl value=\"http://localhost:" + ourPort + "/Patient/1\"/>"));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -177,6 +177,42 @@ public class AuthorizationInterceptorDstu2Test {
|
|||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBatchWhenTransactionAllowed() throws Exception {
|
||||
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
||||
@Override
|
||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||
//@formatter:off
|
||||
return new RuleBuilder()
|
||||
.allow("Rule 1").transaction().withAnyOperation().andApplyNormalRules().andThen()
|
||||
.allow("Rule 2").write().allResources().inCompartment("Patient", new IdDt("Patient/1")).andThen()
|
||||
.allow("Rule 2").read().allResources().inCompartment("Patient", new IdDt("Patient/1")).andThen()
|
||||
.build();
|
||||
//@formatter:on
|
||||
}
|
||||
});
|
||||
|
||||
Bundle input = new Bundle();
|
||||
input.setType(BundleTypeEnum.BATCH);
|
||||
input.addEntry().setResource(createPatient(1)).getRequest().setUrl("/Patient");
|
||||
|
||||
Bundle output = new Bundle();
|
||||
output.setType(BundleTypeEnum.TRANSACTION_RESPONSE);
|
||||
output.addEntry().getResponse().setLocation("/Patient/1");
|
||||
|
||||
HttpPost httpPost;
|
||||
HttpResponse status;
|
||||
String response;
|
||||
|
||||
ourReturn = Arrays.asList((IResource)output);
|
||||
ourHitMethod = false;
|
||||
httpPost = new HttpPost("http://localhost:" + ourPort + "/");
|
||||
httpPost.setEntity(createFhirResourceEntity(input));
|
||||
status = ourClient.execute(httpPost);
|
||||
extractResponseAndClose(status);
|
||||
assertEquals(401, status.getStatusLine().getStatusCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMetadataDeny() throws Exception {
|
||||
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.ALLOW) {
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.dstu2.composite.HumanNameDt;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||
import ca.uhn.fhir.rest.annotation.RequiredParam;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.rest.param.TokenParam;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
|
||||
public class SearchWithGenericListHl7OrgDstu2Test {
|
||||
|
||||
private static CloseableHttpClient ourClient;
|
||||
private static FhirContext ourCtx = FhirContext.forDstu2();
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchWithGenericListHl7OrgDstu2Test.class);
|
||||
private static int ourPort;
|
||||
private static Server ourServer;
|
||||
private static String ourLastMethod;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ourLastMethod = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* See #291
|
||||
*/
|
||||
@Test
|
||||
public void testSearch() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo&_pretty=true");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertEquals("searchByIdentifier", ourLastMethod);
|
||||
assertThat(responseContent, containsString("<family value=\"FAMILY\""));
|
||||
assertThat(responseContent, containsString("<fullUrl value=\"http://localhost:" + ourPort + "/Patient/1\"/>"));
|
||||
}
|
||||
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() throws Exception {
|
||||
ourServer.stop();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
ourPort = PortUtil.findFreePort();
|
||||
ourServer = new Server(ourPort);
|
||||
|
||||
DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider();
|
||||
|
||||
ServletHandler proxyHandler = new ServletHandler();
|
||||
RestfulServer servlet = new RestfulServer(ourCtx);
|
||||
servlet.setPagingProvider(new FifoMemoryPagingProvider(10));
|
||||
|
||||
servlet.setResourceProviders(patientProvider);
|
||||
ServletHolder servletHolder = new ServletHolder(servlet);
|
||||
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
||||
ourServer.setHandler(proxyHandler);
|
||||
ourServer.start();
|
||||
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
builder.setConnectionManager(connectionManager);
|
||||
ourClient = builder.build();
|
||||
|
||||
}
|
||||
|
||||
public static class DummyPatientResourceProvider implements IResourceProvider {
|
||||
|
||||
@Override
|
||||
public Class<? extends IResource> getResourceType() {
|
||||
return Patient.class;
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Search()
|
||||
public List searchByIdentifier(
|
||||
@RequiredParam(name=Patient.SP_IDENTIFIER) TokenParam theIdentifier) {
|
||||
ourLastMethod = "searchByIdentifier";
|
||||
ArrayList<Patient> retVal = new ArrayList<Patient>();
|
||||
retVal.add((Patient) new Patient().addName(new HumanNameDt().addFamily("FAMILY")).setId("1"));
|
||||
return retVal;
|
||||
}
|
||||
//@formatter:on
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue