diff --git a/examples/pom.xml b/examples/pom.xml
index 11f732fb672..9e6fd9ab937 100644
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -92,6 +92,12 @@
org.springframework
spring-web
+
+
+ org.slf4j
+ slf4j-simple
+
+
diff --git a/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/interceptor/SimpleRequestHeaderInterceptor.java b/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/interceptor/SimpleRequestHeaderInterceptor.java
index 72edbf83fa7..ca850dba4b3 100644
--- a/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/interceptor/SimpleRequestHeaderInterceptor.java
+++ b/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/interceptor/SimpleRequestHeaderInterceptor.java
@@ -32,6 +32,8 @@ import org.apache.commons.lang3.Validate;
/**
* This interceptor adds an arbitrary header to requests made by this client. Both the
* header name and the header value are specified by the calling code.
+ *
+ * @see AdditionalRequestHeadersInterceptor for a more advanced version of this interceptor which can add multiple headers
*/
public class SimpleRequestHeaderInterceptor implements IClientInterceptor {
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java
index 5a458068ef2..5c6981cccb5 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java
@@ -3149,16 +3149,18 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
.count(1)
.execute();
- ourLog.info("** Done searching with count of 1");
+ ourLog.info("** Done searching in {}ms with count of 1", sw.getMillis());
ourLog.info(myCapturingInterceptor.getLastResponse().getAllHeaders().toString());
assertThat(myCapturingInterceptor.getLastResponse().getHeaders(Constants.HEADER_X_CACHE), Matchers.empty());
assertThat(myCapturingInterceptor.getLastResponse().getHeaders(Constants.HEADER_X_CACHE.toLowerCase()),Matchers.empty());
+ String msg = "Total is " + found.getTotalElement().getValue() + " and took " + sw.getMillis() + " millis";
+
// If this fails under load, try increasing the throttle above
- assertEquals(null, found.getTotalElement().getValue());
- assertEquals(1, found.getEntry().size());
- assertThat(sw.getMillis(), lessThan(1000L));
+ assertEquals(msg,null, found.getTotalElement().getValue());
+ assertEquals(msg, 1, found.getEntry().size());
+ assertThat(msg, sw.getMillis(), lessThan(1000L));
}
diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/interceptor/AdditionalRequestHeadersInterceptorR4Test.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/interceptor/AdditionalRequestHeadersInterceptorR4Test.java
new file mode 100644
index 00000000000..5989618acb0
--- /dev/null
+++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/interceptor/AdditionalRequestHeadersInterceptorR4Test.java
@@ -0,0 +1,2202 @@
+package ca.uhn.fhir.rest.server.interceptor;
+
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.context.api.AddProfileTagEnum;
+import ca.uhn.fhir.rest.annotation.*;
+import ca.uhn.fhir.rest.api.Constants;
+import ca.uhn.fhir.rest.api.*;
+import ca.uhn.fhir.rest.api.server.IRequestOperationCallback;
+import ca.uhn.fhir.rest.api.server.RequestDetails;
+import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider;
+import ca.uhn.fhir.rest.server.IResourceProvider;
+import ca.uhn.fhir.rest.server.RestfulServer;
+import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
+import ca.uhn.fhir.rest.server.interceptor.auth.AuthorizationInterceptor;
+import ca.uhn.fhir.rest.server.interceptor.auth.IAuthRule;
+import ca.uhn.fhir.rest.server.interceptor.auth.PolicyEnum;
+import ca.uhn.fhir.rest.server.interceptor.auth.RuleBuilder;
+import ca.uhn.fhir.util.PortUtil;
+import ca.uhn.fhir.util.TestUtil;
+import org.apache.commons.io.IOUtils;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.*;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
+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.hl7.fhir.instance.model.api.IBaseResource;
+import org.hl7.fhir.r4.model.*;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import static org.apache.commons.lang3.StringUtils.isNotBlank;
+import static org.hamcrest.Matchers.containsString;
+import static org.junit.Assert.*;
+
+public class AdditionalRequestHeadersInterceptorR4Test {
+
+ private static final String ERR403 = "{\"resourceType\":\"OperationOutcome\",\"issue\":[{\"severity\":\"error\",\"code\":\"processing\",\"diagnostics\":\"Access denied by default policy (no applicable rules)\"}]}";
+ private static CloseableHttpClient ourClient;
+ private static String ourConditionalCreateId;
+ private static FhirContext ourCtx = FhirContext.forR4();
+ private static boolean ourHitMethod;
+ private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(AdditionalRequestHeadersInterceptorR4Test.class);
+ private static int ourPort;
+ private static List ourReturn;
+ private static Server ourServer;
+ private static RestfulServer ourServlet;
+
+ @Before
+ public void before() {
+ ourCtx.setAddProfileTagWhenEncoding(AddProfileTagEnum.NEVER);
+ for (IServerInterceptor next : new ArrayList<>(ourServlet.getInterceptors())) {
+ ourServlet.unregisterInterceptor(next);
+ }
+ ourReturn = null;
+ ourHitMethod = false;
+ ourConditionalCreateId = "1123";
+ }
+
+ private Resource createCarePlan(Integer theId, String theSubjectId) {
+ CarePlan retVal = new CarePlan();
+ if (theId != null) {
+ retVal.setId(new IdType("CarePlan", (long) theId));
+ }
+ retVal.setSubject(new Reference("Patient/" + theSubjectId));
+ return retVal;
+ }
+
+ private HttpEntity createFhirResourceEntity(IBaseResource theResource) {
+ String out = ourCtx.newJsonParser().encodeResourceToString(theResource);
+ return new StringEntity(out, ContentType.create(Constants.CT_FHIR_JSON, "UTF-8"));
+ }
+
+ private Resource createObservation(Integer theId, String theSubjectId) {
+ Observation retVal = new Observation();
+ if (theId != null) {
+ retVal.setId(new IdType("Observation", (long) theId));
+ }
+ retVal.getCode().setText("OBS");
+ retVal.setSubject(new Reference(theSubjectId));
+ return retVal;
+ }
+
+ private Resource createPatient(Integer theId) {
+ Patient retVal = new Patient();
+ if (theId != null) {
+ retVal.setId(new IdType("Patient", (long) theId));
+ }
+ retVal.addName().setFamily("FAM");
+ return retVal;
+ }
+
+ private Resource createPatient(Integer theId, int theVersion) {
+ Resource retVal = createPatient(theId);
+ retVal.setId(retVal.getIdElement().withVersion(Integer.toString(theVersion)));
+ return retVal;
+ }
+
+ private String extractResponseAndClose(HttpResponse status) throws IOException {
+ if (status.getEntity() == null) {
+ return null;
+ }
+ String responseContent;
+ responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
+ IOUtils.closeQuietly(status.getEntity().getContent());
+ return responseContent;
+ }
+
+ @Test
+ public void testAllowAll() throws Exception {
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .deny("Rule 1").read().resourcesOfType(Patient.class).withAnyId().andThen()
+ .allowAll("Default Rule")
+ .build();
+ }
+ });
+
+ HttpGet httpGet;
+ HttpResponse status;
+ String response;
+
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createObservation(10, "Patient/2"));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Observation/10");
+ status = ourClient.execute(httpGet);
+ extractResponseAndClose(status);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createPatient(2));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertThat(response, containsString("Access denied by rule: Rule 1"));
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ ourHitMethod = false;
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1/$validate");
+ status = ourClient.execute(httpGet);
+ extractResponseAndClose(status);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ }
+
+ /**
+ * #528
+ */
+ @Test
+ public void testAllowByCompartmentWithAnyType() throws Exception {
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder().allow("Rule 1").read().allResources().inCompartment("Patient", new IdType("Patient/845bd9f1-3635-4866-a6c8-1ca085df5c1a")).andThen().denyAll().build();
+ }
+ });
+
+ HttpGet httpGet;
+ HttpResponse status;
+
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createCarePlan(10, "845bd9f1-3635-4866-a6c8-1ca085df5c1a"));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/CarePlan/135154");
+ status = ourClient.execute(httpGet);
+ extractResponseAndClose(status);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createCarePlan(10, "FOO"));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/CarePlan/135154");
+ status = ourClient.execute(httpGet);
+ extractResponseAndClose(status);
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ }
+
+ /**
+ * #528
+ */
+ @Test
+ public void testAllowByCompartmentWithType() throws Exception {
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder().allow("Rule 1").read().resourcesOfType(CarePlan.class).inCompartment("Patient", new IdType("Patient/845bd9f1-3635-4866-a6c8-1ca085df5c1a")).andThen().denyAll()
+ .build();
+ }
+ });
+
+ HttpGet httpGet;
+ HttpResponse status;
+
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createCarePlan(10, "845bd9f1-3635-4866-a6c8-1ca085df5c1a"));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/CarePlan/135154");
+ status = ourClient.execute(httpGet);
+ extractResponseAndClose(status);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createCarePlan(10, "FOO"));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/CarePlan/135154");
+ status = ourClient.execute(httpGet);
+ extractResponseAndClose(status);
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+ }
+
+ @Test
+ public void testBatchWhenOnlyTransactionAllowed() throws Exception {
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("Rule 1").transaction().withAnyOperation().andApplyNormalRules().andThen()
+ .allow("Rule 2").write().allResources().inCompartment("Patient", new IdType("Patient/1")).andThen()
+ .allow("Rule 2").read().allResources().inCompartment("Patient", new IdType("Patient/1")).andThen()
+ .build();
+ }
+ });
+
+ Bundle input = new Bundle();
+ input.setType(Bundle.BundleType.BATCH);
+ input.addEntry().setResource(createPatient(1)).getRequest().setUrl("/Patient").setMethod(Bundle.HTTPVerb.POST);
+
+ Bundle output = new Bundle();
+ output.setType(Bundle.BundleType.TRANSACTIONRESPONSE);
+ output.addEntry().getResponse().setLocation("/Patient/1");
+
+ HttpPost httpPost;
+ HttpResponse status;
+
+ ourReturn = Collections.singletonList((Resource) output);
+ ourHitMethod = false;
+ httpPost = new HttpPost("http://localhost:" + ourPort + "/");
+ httpPost.setEntity(createFhirResourceEntity(input));
+ status = ourClient.execute(httpPost);
+ extractResponseAndClose(status);
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ }
+
+ @Test
+ public void testBatchWhenTransactionReadDenied() throws Exception {
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("Rule 1").transaction().withAnyOperation().andApplyNormalRules().andThen()
+ .allow("Rule 2").write().allResources().inCompartment("Patient", new IdType("Patient/1")).andThen()
+ .allow("Rule 2").read().allResources().inCompartment("Patient", new IdType("Patient/1")).andThen()
+ .build();
+ }
+ });
+
+ Bundle input = new Bundle();
+ input.setType(Bundle.BundleType.BATCH);
+ input.addEntry().setResource(createPatient(1)).getRequest().setUrl("/Patient").setMethod(Bundle.HTTPVerb.POST);
+
+ Bundle output = new Bundle();
+ output.setType(Bundle.BundleType.TRANSACTIONRESPONSE);
+ output.addEntry().setResource(createPatient(2));
+
+ HttpPost httpPost;
+ HttpResponse status;
+
+ ourReturn = Collections.singletonList((Resource) output);
+ ourHitMethod = false;
+ httpPost = new HttpPost("http://localhost:" + ourPort + "/");
+ httpPost.setEntity(createFhirResourceEntity(input));
+ status = ourClient.execute(httpPost);
+ extractResponseAndClose(status);
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ }
+
+ @Test
+ public void testBatchWhenTransactionWrongBundleType() throws Exception {
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("Rule 1").transaction().withAnyOperation().andApplyNormalRules().andThen()
+ .allow("Rule 2").write().allResources().inCompartment("Patient", new IdType("Patient/1")).andThen()
+ .allow("Rule 2").read().allResources().inCompartment("Patient", new IdType("Patient/1")).andThen()
+ .build();
+ }
+ });
+
+ Bundle input = new Bundle();
+ input.setType(Bundle.BundleType.COLLECTION);
+ input.addEntry().setResource(createPatient(1)).getRequest().setUrl("/Patient").setMethod(Bundle.HTTPVerb.POST);
+
+ Bundle output = new Bundle();
+ output.setType(Bundle.BundleType.TRANSACTIONRESPONSE);
+ output.addEntry().setResource(createPatient(1));
+
+ HttpPost httpPost;
+ HttpResponse status;
+ String response;
+
+ ourReturn = Collections.singletonList((Resource) output);
+ ourHitMethod = false;
+ httpPost = new HttpPost("http://localhost:" + ourPort + "/");
+ httpPost.setEntity(createFhirResourceEntity(input));
+ status = ourClient.execute(httpPost);
+ response = extractResponseAndClose(status);
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertEquals(ERR403, response);
+ }
+
+ @Test
+ public void testDeleteByCompartment() throws Exception {
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("Rule 1").delete().resourcesOfType(Patient.class).inCompartment("Patient", new IdType("Patient/1")).andThen()
+ .allow("Rule 2").delete().resourcesOfType(Observation.class).inCompartment("Patient", new IdType("Patient/1"))
+ .build();
+ }
+ });
+
+ HttpDelete httpDelete;
+ HttpResponse status;
+
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createPatient(2));
+ httpDelete = new HttpDelete("http://localhost:" + ourPort + "/Patient/2");
+ status = ourClient.execute(httpDelete);
+ extractResponseAndClose(status);
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createPatient(1));
+ httpDelete = new HttpDelete("http://localhost:" + ourPort + "/Patient/1");
+ status = ourClient.execute(httpDelete);
+ extractResponseAndClose(status);
+ assertEquals(204, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+ }
+
+ @Test
+ public void testDenyAll() throws Exception {
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow().read().resourcesOfType(Patient.class).withAnyId().andThen()
+ .denyAll("Default Rule")
+ .build();
+ }
+ });
+
+ HttpGet httpGet;
+ HttpResponse status;
+ String response;
+
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createPatient(2));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
+ status = ourClient.execute(httpGet);
+ extractResponseAndClose(status);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createObservation(10, "Patient/2"));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Observation/10");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertThat(response, containsString("Access denied by rule: Default Rule"));
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertFalse(ourHitMethod);
+
+ ourHitMethod = false;
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1/$validate");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertThat(response, containsString("Access denied by rule: Default Rule"));
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertFalse(ourHitMethod);
+
+ ourHitMethod = false;
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1/$opName");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertThat(response, containsString("Access denied by rule: Default Rule"));
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertFalse(ourHitMethod);
+ }
+
+ /**
+ * #528
+ */
+ @Test
+ public void testDenyByCompartmentWithAnyType() throws Exception {
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder().deny("Rule 1").read().allResources().inCompartment("Patient", new IdType("Patient/845bd9f1-3635-4866-a6c8-1ca085df5c1a")).andThen().allowAll().build();
+ }
+ });
+
+ HttpGet httpGet;
+ HttpResponse status;
+
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createCarePlan(10, "845bd9f1-3635-4866-a6c8-1ca085df5c1a"));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/CarePlan/135154");
+ status = ourClient.execute(httpGet);
+ extractResponseAndClose(status);
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createCarePlan(10, "FOO"));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/CarePlan/135154");
+ status = ourClient.execute(httpGet);
+ extractResponseAndClose(status);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ }
+
+ /**
+ * #528
+ */
+ @Test
+ public void testDenyByCompartmentWithType() throws Exception {
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder().deny("Rule 1").read().resourcesOfType(CarePlan.class).inCompartment("Patient", new IdType("Patient/845bd9f1-3635-4866-a6c8-1ca085df5c1a")).andThen().allowAll()
+ .build();
+ }
+ });
+
+ HttpGet httpGet;
+ HttpResponse status;
+
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createCarePlan(10, "845bd9f1-3635-4866-a6c8-1ca085df5c1a"));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/CarePlan/135154");
+ status = ourClient.execute(httpGet);
+ extractResponseAndClose(status);
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createCarePlan(10, "FOO"));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/CarePlan/135154");
+ status = ourClient.execute(httpGet);
+ extractResponseAndClose(status);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+ }
+
+ @Test
+ public void testHistoryWithReadAll() throws Exception {
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("Rule 1").read().allResources().withAnyId()
+ .build();
+ }
+ });
+
+ HttpGet httpGet;
+ HttpResponse status;
+
+ ourReturn = Collections.singletonList(createPatient(2, 1));
+
+ ourHitMethod = false;
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/_history");
+ status = ourClient.execute(httpGet);
+ extractResponseAndClose(status);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ ourHitMethod = false;
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/_history");
+ status = ourClient.execute(httpGet);
+ extractResponseAndClose(status);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ ourHitMethod = false;
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1/_history");
+ status = ourClient.execute(httpGet);
+ extractResponseAndClose(status);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+ }
+
+ @Test
+ public void testMetadataAllow() throws Exception {
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("Rule 1").metadata()
+ .build();
+ }
+ });
+
+ HttpGet httpGet;
+ HttpResponse status;
+
+ ourReturn = Collections.singletonList(createPatient(2));
+ ourHitMethod = false;
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/metadata");
+ status = ourClient.execute(httpGet);
+ extractResponseAndClose(status);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ }
+
+ @Test
+ public void testMetadataDeny() throws Exception {
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.ALLOW) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .deny("Rule 1").metadata()
+ .build();
+ }
+ });
+
+ HttpGet httpGet;
+ HttpResponse status;
+
+ ourReturn = Collections.singletonList(createPatient(2));
+ ourHitMethod = false;
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/metadata");
+ status = ourClient.execute(httpGet);
+ extractResponseAndClose(status);
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ }
+
+ @Test
+ public void testOperationAnyName() throws Exception {
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("RULE 1").operation().withAnyName().onServer().andThen()
+ .build();
+ }
+ });
+
+ HttpGet httpGet;
+ HttpResponse status;
+
+ // Server
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createObservation(10, "Patient/2"));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/$opName");
+ status = ourClient.execute(httpGet);
+ String response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ }
+
+ @Test
+ public void testOperationByInstanceOfTypeAllowed() throws Exception {
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("Rule 1").operation().named("everything").onInstancesOfType(Patient.class)
+ .build();
+ }
+ });
+
+ HttpGet httpGet;
+ HttpResponse status;
+ String response;
+
+ ourReturn = new ArrayList<>();
+ ourHitMethod = false;
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1/$everything");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ assertThat(response, containsString("Bundle"));
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertEquals(true, ourHitMethod);
+
+ ourReturn = new ArrayList<>();
+ ourHitMethod = false;
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Encounter/1/$everything");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ assertThat(response, containsString("OperationOutcome"));
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertEquals(false, ourHitMethod);
+
+ }
+
+ @Test
+ public void testOperationByInstanceOfTypeWithInvalidReturnValue() throws Exception {
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("Rule 1").operation().named("everything").onInstancesOfType(Patient.class).andThen()
+ .allow("Rule 2").read().allResources().inCompartment("Patient", new IdType("Patient/1")).andThen()
+ .build();
+ }
+ });
+
+ HttpGet httpGet;
+ HttpResponse status;
+ String response;
+
+ // With a return value we don't allow
+ ourReturn = Collections.singletonList(createPatient(222));
+ ourHitMethod = false;
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1/$everything");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ assertThat(response, containsString("OperationOutcome"));
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertEquals(true, ourHitMethod);
+
+ // With a return value we do
+ ourReturn = Collections.singletonList(createPatient(1));
+ ourHitMethod = false;
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1/$everything");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ assertThat(response, containsString("Bundle"));
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertEquals(true, ourHitMethod);
+
+ }
+
+ @Test
+ public void testOperationByInstanceOfTypeWithReturnValue() throws Exception {
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("Rule 1").operation().named("everything").onInstancesOfType(Patient.class)
+ .build();
+ }
+ });
+
+ HttpGet httpGet;
+ HttpResponse status;
+ String response;
+
+ ourReturn = new ArrayList<>();
+ ourHitMethod = false;
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1/$everything");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ assertThat(response, containsString("Bundle"));
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertEquals(true, ourHitMethod);
+
+ ourReturn = new ArrayList<>();
+ ourHitMethod = false;
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Encounter/1/$everything");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ assertThat(response, containsString("OperationOutcome"));
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertEquals(false, ourHitMethod);
+ }
+
+ @Test
+ public void testOperationInstanceLevel() throws Exception {
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("RULE 1").operation().named("opName").onInstance(new IdType("http://example.com/Patient/1/_history/2")).andThen()
+ .build();
+ }
+ });
+
+ HttpGet httpGet;
+ HttpResponse status;
+ String response;
+
+ // Server
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createObservation(10, "Patient/2"));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/$opName");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ assertThat(response, containsString("Access denied by default policy"));
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertFalse(ourHitMethod);
+
+ // Type
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createPatient(2));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$opName");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertThat(response, containsString("Access denied by default policy"));
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertFalse(ourHitMethod);
+
+ // Instance
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createPatient(2));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1/$opName");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ // Wrong instance
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createPatient(2));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/2/$opName");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertThat(response, containsString("Access denied by default policy"));
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertFalse(ourHitMethod);
+
+ }
+
+ @Test
+ public void testOperationInstanceLevelAnyInstance() throws Exception {
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("RULE 1").operation().named("opName").onAnyInstance().andThen()
+ .build();
+ }
+ });
+
+ HttpGet httpGet;
+ HttpResponse status;
+ String response;
+
+ // Server
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createObservation(10, "Patient/2"));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/$opName");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ assertThat(response, containsString("Access denied by default policy"));
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertFalse(ourHitMethod);
+
+ // Type
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createPatient(2));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$opName");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertThat(response, containsString("Access denied by default policy"));
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertFalse(ourHitMethod);
+
+ // Instance
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createPatient(2));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1/$opName");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ // Another Instance
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createPatient(2));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Observation/2/$opName");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ // Wrong name
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createPatient(2));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/2/$opName2");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertThat(response, containsString("Access denied by default policy"));
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertFalse(ourHitMethod);
+
+ }
+
+ @Test
+ public void testOperationNotAllowedWithWritePermissiom() throws Exception {
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("RULE 1").write().allResources().withAnyId().andThen()
+ .build();
+ }
+ });
+
+ HttpGet httpGet;
+ HttpResponse status;
+ String response;
+
+ // Server
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createObservation(10, "Patient/2"));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/$opName");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ assertThat(response, containsString("Access denied by default policy"));
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertFalse(ourHitMethod);
+
+ // System
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createPatient(2));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/$opName");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertFalse(ourHitMethod);
+
+ // Type
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createPatient(2));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$opName");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertFalse(ourHitMethod);
+
+ // Instance
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createPatient(2));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123/$opName");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertFalse(ourHitMethod);
+ }
+
+ @Test
+ public void testOperationServerLevel() throws Exception {
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("RULE 1").operation().named("opName").onServer().andThen()
+ .build();
+ }
+ });
+
+ HttpGet httpGet;
+ HttpResponse status;
+ String response;
+
+ // Server
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createObservation(10, "Patient/2"));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/$opName");
+ status = ourClient.execute(httpGet);
+ extractResponseAndClose(status);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ // Type
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createPatient(2));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$opName");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertThat(response, containsString("Access denied by default policy"));
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertFalse(ourHitMethod);
+
+ // Instance
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createPatient(2));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1/$opName");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertThat(response, containsString("Access denied by default policy"));
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertFalse(ourHitMethod);
+ }
+
+ @Test
+ public void testOperationTypeLevel() throws Exception {
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("RULE 1").operation().named("opName").onType(Patient.class).andThen()
+ .build();
+ }
+ });
+
+ HttpGet httpGet;
+ HttpResponse status;
+ String response;
+
+ // Server
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createObservation(10, "Patient/2"));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/$opName");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ assertThat(response, containsString("Access denied by default policy"));
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertFalse(ourHitMethod);
+
+ // Type
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createPatient(2));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$opName");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ // Wrong type
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createPatient(2));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Observation/1/$opName");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertThat(response, containsString("Access denied by default policy"));
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertFalse(ourHitMethod);
+
+ // Wrong name
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createPatient(2));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1/$opName2");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertThat(response, containsString("Access denied by default policy"));
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertFalse(ourHitMethod);
+
+ // Instance
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createPatient(2));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1/$opName");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertThat(response, containsString("Access denied by default policy"));
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertFalse(ourHitMethod);
+ }
+
+ @Test
+ public void testOperationTypeLevelWildcard() throws Exception {
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("RULE 1").operation().named("opName").onAnyType().andThen()
+ .build();
+ }
+ });
+
+ HttpGet httpGet;
+ HttpResponse status;
+ String response;
+
+ // Server
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createObservation(10, "Patient/2"));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/$opName");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ assertThat(response, containsString("Access denied by default policy"));
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertFalse(ourHitMethod);
+
+ // Type
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createPatient(2));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$opName");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ // Another type
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createPatient(2));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Observation/$opName");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ // Wrong name
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createPatient(2));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$opName2");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertThat(response, containsString("Access denied by default policy"));
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertFalse(ourHitMethod);
+
+ // Instance
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createPatient(2));
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1/$opName");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertThat(response, containsString("Access denied by default policy"));
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertFalse(ourHitMethod);
+ }
+
+ @Test
+ public void testReadByAnyId() throws Exception {
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("Rule 1").read().resourcesOfType(Patient.class).withAnyId()
+ .build();
+ }
+ });
+
+ HttpGet httpGet;
+ HttpResponse status;
+ String response;
+
+ ourReturn = Collections.singletonList(createPatient(2));
+ ourHitMethod = false;
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
+ status = ourClient.execute(httpGet);
+ extractResponseAndClose(status);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ ourReturn = Collections.singletonList(createPatient(2));
+ ourHitMethod = false;
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1/_history/222");
+ status = ourClient.execute(httpGet);
+ extractResponseAndClose(status);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ ourReturn = Collections.singletonList(createObservation(10, "Patient/2"));
+ ourHitMethod = false;
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Observation/10");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertThat(response, containsString("Access denied by default policy (no applicable rules)"));
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertFalse(ourHitMethod);
+
+ ourReturn = Arrays.asList(createPatient(1), createObservation(10, "Patient/2"));
+ ourHitMethod = false;
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertThat(response, containsString("Access denied by default policy (no applicable rules)"));
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ ourReturn = Arrays.asList(createPatient(2), createObservation(10, "Patient/1"));
+ ourHitMethod = false;
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertThat(response, containsString("Access denied by default policy (no applicable rules)"));
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ }
+
+ @Test
+ public void testReadByCompartmentRight() throws Exception {
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("Rule 1").read().resourcesOfType(Patient.class).inCompartment("Patient", new IdType("Patient/1")).andThen()
+ .allow("Rule 2").read().resourcesOfType(Observation.class).inCompartment("Patient", new IdType("Patient/1"))
+ .build();
+ }
+ });
+
+ HttpGet httpGet;
+ HttpResponse status;
+
+ ourReturn = Collections.singletonList(createPatient(1));
+ ourHitMethod = false;
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
+ status = ourClient.execute(httpGet);
+ extractResponseAndClose(status);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ ourReturn = Collections.singletonList(createObservation(10, "Patient/1"));
+ ourHitMethod = false;
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Observation/10");
+ status = ourClient.execute(httpGet);
+ extractResponseAndClose(status);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ ourReturn = Arrays.asList(createPatient(1), createObservation(10, "Patient/1"));
+ ourHitMethod = false;
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient");
+ status = ourClient.execute(httpGet);
+ extractResponseAndClose(status);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ }
+
+ @Test
+ public void testReadPageRight() throws Exception {
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("Rule 1").read().resourcesOfType(Patient.class).inCompartment("Patient", new IdType("Patient/1"))
+ .build();
+ }
+ });
+
+ HttpGet httpGet;
+ HttpResponse status;
+ String respString;
+ Bundle respBundle;
+
+ ourReturn = new ArrayList<>();
+ for (int i = 0; i < 10; i++) {
+ ourReturn.add(createPatient(1));
+ }
+
+ ourHitMethod = false;
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_count=5&_format=json");
+ status = ourClient.execute(httpGet);
+ respString = extractResponseAndClose(status);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+ respBundle = ourCtx.newJsonParser().parseResource(Bundle.class, respString);
+ assertEquals(5, respBundle.getEntry().size());
+ assertEquals(10, respBundle.getTotal());
+ assertEquals("Patient/1", respBundle.getEntry().get(0).getResource().getIdElement().toUnqualifiedVersionless().getValue());
+ assertNotNull(respBundle.getLink("next"));
+
+ // Load next page
+
+ ourHitMethod = false;
+ httpGet = new HttpGet(respBundle.getLink("next").getUrl());
+ status = ourClient.execute(httpGet);
+ respString = extractResponseAndClose(status);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertFalse(ourHitMethod);
+ respBundle = ourCtx.newJsonParser().parseResource(Bundle.class, respString);
+ assertEquals(5, respBundle.getEntry().size());
+ assertEquals(10, respBundle.getTotal());
+ assertEquals("Patient/1", respBundle.getEntry().get(0).getResource().getIdElement().toUnqualifiedVersionless().getValue());
+ assertNull(respBundle.getLink("next"));
+
+ }
+
+ @Test
+ public void testReadPageWrong() throws Exception {
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("Rule 1").read().resourcesOfType(Patient.class).inCompartment("Patient", new IdType("Patient/1"))
+ .build();
+ }
+ });
+
+ HttpGet httpGet;
+ HttpResponse status;
+ String respString;
+ Bundle respBundle;
+
+ ourReturn = new ArrayList<>();
+ for (int i = 0; i < 5; i++) {
+ ourReturn.add(createPatient(1));
+ }
+ for (int i = 0; i < 5; i++) {
+ ourReturn.add(createPatient(2));
+ }
+
+ ourHitMethod = false;
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_count=5&_format=json");
+ status = ourClient.execute(httpGet);
+ respString = extractResponseAndClose(status);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+ respBundle = ourCtx.newJsonParser().parseResource(Bundle.class, respString);
+ assertEquals(5, respBundle.getEntry().size());
+ assertEquals(10, respBundle.getTotal());
+ assertEquals("Patient/1", respBundle.getEntry().get(0).getResource().getIdElement().toUnqualifiedVersionless().getValue());
+ assertNotNull(respBundle.getLink("next"));
+
+ // Load next page
+
+ ourHitMethod = false;
+ httpGet = new HttpGet(respBundle.getLink("next").getUrl());
+ status = ourClient.execute(httpGet);
+ respString = extractResponseAndClose(status);
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertFalse(ourHitMethod);
+
+ }
+
+ @Test
+ public void testReadByCompartmentWrong() throws Exception {
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("Rule 1").read().resourcesOfType(Patient.class).inCompartment("Patient", new IdType("Patient/1")).andThen()
+ .allow("Rule 2").read().resourcesOfType(Observation.class).inCompartment("Patient", new IdType("Patient/1"))
+ .build();
+ }
+ });
+
+ HttpGet httpGet;
+ HttpResponse status;
+ String response;
+
+ ourReturn = Collections.singletonList(createPatient(2));
+ ourHitMethod = false;
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/2");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertThat(response, containsString("Access denied by default policy (no applicable rules)"));
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ ourReturn = Collections.singletonList(createObservation(10, "Patient/2"));
+ ourHitMethod = false;
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Observation/10");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertThat(response, containsString("Access denied by default policy (no applicable rules)"));
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ ourReturn = Collections.singletonList(createCarePlan(10, "Patient/2"));
+ ourHitMethod = false;
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/CarePlan/10");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertThat(response, containsString("Access denied by default policy (no applicable rules)"));
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertFalse(ourHitMethod);
+
+ ourReturn = Arrays.asList(createPatient(1), createObservation(10, "Patient/2"));
+ ourHitMethod = false;
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertThat(response, containsString("Access denied by default policy (no applicable rules)"));
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ ourReturn = Arrays.asList(createPatient(2), createObservation(10, "Patient/1"));
+ ourHitMethod = false;
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertThat(response, containsString("Access denied by default policy (no applicable rules)"));
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ }
+
+ @Test
+ public void testTransactionWriteGood() throws Exception {
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("Rule 1").transaction().withAnyOperation().andApplyNormalRules().andThen()
+ .allow("Rule 2").write().allResources().inCompartment("Patient", new IdType("Patient/1")).andThen()
+ .allow("Rule 2").read().allResources().inCompartment("Patient", new IdType("Patient/1")).andThen()
+ .build();
+ }
+ });
+
+ Bundle input = new Bundle();
+ input.setType(Bundle.BundleType.TRANSACTION);
+ input.addEntry().setResource(createPatient(1)).getRequest().setUrl("/Patient").setMethod(Bundle.HTTPVerb.PUT);
+
+ Bundle output = new Bundle();
+ output.setType(Bundle.BundleType.TRANSACTIONRESPONSE);
+ output.addEntry().getResponse().setLocation("/Patient/1");
+
+ HttpPost httpPost;
+ HttpResponse status;
+
+ ourReturn = Collections.singletonList((Resource) output);
+ ourHitMethod = false;
+ httpPost = new HttpPost("http://localhost:" + ourPort + "/");
+ httpPost.setEntity(createFhirResourceEntity(input));
+ status = ourClient.execute(httpPost);
+ extractResponseAndClose(status);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ }
+
+ @Test
+ public void testWriteByCompartmentCreate() throws Exception {
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("Rule 1").write().resourcesOfType(Patient.class).inCompartment("Patient", new IdType("Patient/1")).andThen()
+ .allow("Rule 1b").write().resourcesOfType(Patient.class).inCompartment("Patient", new IdType("Patient/1123")).andThen()
+ .allow("Rule 2").write().resourcesOfType(Observation.class).inCompartment("Patient", new IdType("Patient/1"))
+ .build();
+ }
+ });
+
+ HttpEntityEnclosingRequestBase httpPost;
+ HttpResponse status;
+ String response;
+
+ ourHitMethod = false;
+ httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
+ httpPost.setEntity(createFhirResourceEntity(createPatient(null)));
+ status = ourClient.execute(httpPost);
+ response = extractResponseAndClose(status);
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertEquals(ERR403, response);
+ assertFalse(ourHitMethod);
+
+ // Conditional
+ ourHitMethod = false;
+ httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
+ httpPost.addHeader("If-None-Exist", "Patient?foo=bar");
+ httpPost.setEntity(createFhirResourceEntity(createPatient(null)));
+ status = ourClient.execute(httpPost);
+ response = extractResponseAndClose(status);
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertEquals(ERR403, response);
+ assertFalse(ourHitMethod);
+
+ ourHitMethod = false;
+ httpPost = new HttpPost("http://localhost:" + ourPort + "/Observation");
+ httpPost.setEntity(createFhirResourceEntity(createObservation(null, "Patient/2")));
+ status = ourClient.execute(httpPost);
+ response = extractResponseAndClose(status);
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertEquals(ERR403, response);
+ assertFalse(ourHitMethod);
+
+ ourHitMethod = false;
+ httpPost = new HttpPost("http://localhost:" + ourPort + "/Observation");
+ httpPost.setEntity(createFhirResourceEntity(createObservation(null, "Patient/1")));
+ status = ourClient.execute(httpPost);
+ response = extractResponseAndClose(status);
+ assertEquals(201, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+ }
+
+ @Test
+ public void testWriteByCompartmentCreateConditionalResolvesToValid() throws Exception {
+ ourConditionalCreateId = "1";
+
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("Rule 1").write().resourcesOfType(Patient.class).inCompartment("Patient", new IdType("Patient/1")).andThen()
+ .allow("Rule 2").createConditional().resourcesOfType(Patient.class)
+ .build();
+ }
+ });
+
+ HttpEntityEnclosingRequestBase httpPost;
+ HttpResponse status;
+
+ ourHitMethod = false;
+ httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
+ httpPost.addHeader(Constants.HEADER_IF_NONE_EXIST, "foo=bar");
+ httpPost.setEntity(createFhirResourceEntity(createPatient(null)));
+ status = ourClient.execute(httpPost);
+ String response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertEquals(201, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ }
+
+ @Test
+ public void testWriteByCompartmentDeleteConditionalResolvesToValid() throws Exception {
+ ourConditionalCreateId = "1";
+
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("Rule 1").delete().resourcesOfType(Patient.class).inCompartment("Patient", new IdType("Patient/1")).andThen()
+ .allow("Rule 2").deleteConditional().resourcesOfType(Patient.class)
+ .build();
+ }
+ });
+
+ HttpDelete httpDelete;
+ HttpResponse status;
+
+ ourReturn = Collections.singletonList(createPatient(1));
+
+ ourHitMethod = false;
+ httpDelete = new HttpDelete("http://localhost:" + ourPort + "/Patient?foo=bar");
+ status = ourClient.execute(httpDelete);
+ String response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertEquals(204, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ }
+
+ @Test
+ public void testWriteByCompartmentDeleteConditionalWithoutDirectMatch() throws Exception {
+ ourConditionalCreateId = "1";
+
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("Rule 2").deleteConditional().resourcesOfType(Patient.class)
+ .build();
+ }
+ });
+
+ HttpDelete httpDelete;
+ HttpResponse status;
+
+ ourReturn = Collections.singletonList(createPatient(1));
+
+ ourHitMethod = false;
+ httpDelete = new HttpDelete("http://localhost:" + ourPort + "/Patient?foo=bar");
+ status = ourClient.execute(httpDelete);
+ String response = extractResponseAndClose(status);
+ ourLog.info(response);
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ }
+
+ @Test
+ public void testWriteByCompartmentDoesntAllowDelete() throws Exception {
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("Rule 1").write().resourcesOfType(Patient.class).inCompartment("Patient", new IdType("Patient/1")).andThen()
+ .allow("Rule 2").write().resourcesOfType(Observation.class).inCompartment("Patient", new IdType("Patient/1"))
+ .build();
+ }
+ });
+
+ HttpDelete httpDelete;
+ HttpResponse status;
+
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createPatient(2));
+ httpDelete = new HttpDelete("http://localhost:" + ourPort + "/Patient/2");
+ status = ourClient.execute(httpDelete);
+ extractResponseAndClose(status);
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ ourHitMethod = false;
+ ourReturn = Collections.singletonList(createPatient(1));
+ httpDelete = new HttpDelete("http://localhost:" + ourPort + "/Patient/1");
+ status = ourClient.execute(httpDelete);
+ extractResponseAndClose(status);
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+ }
+
+ @Test
+ public void testWriteByCompartmentUpdate() throws Exception {
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("Rule 1").write().resourcesOfType(Patient.class).inCompartment("Patient", new IdType("Patient/1")).andThen()
+ .allow("Rule 2").write().resourcesOfType(Observation.class).inCompartment("Patient", new IdType("Patient/1"))
+ .build();
+ }
+ });
+
+ HttpEntityEnclosingRequestBase httpPost;
+ String response;
+ HttpResponse status;
+
+ ourHitMethod = false;
+ httpPost = new HttpPut("http://localhost:" + ourPort + "/Patient/2");
+ httpPost.setEntity(createFhirResourceEntity(createPatient(2)));
+ status = ourClient.execute(httpPost);
+ response = extractResponseAndClose(status);
+ assertEquals(ERR403, response);
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertFalse(ourHitMethod);
+
+ ourHitMethod = false;
+ httpPost = new HttpPut("http://localhost:" + ourPort + "/Patient/1");
+ httpPost.setEntity(createFhirResourceEntity(createPatient(1)));
+ status = ourClient.execute(httpPost);
+ extractResponseAndClose(status);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ // Conditional
+ ourHitMethod = false;
+ httpPost = new HttpPut("http://localhost:" + ourPort + "/Patient?foo=bar");
+ httpPost.setEntity(createFhirResourceEntity(createPatient(1)));
+ status = ourClient.execute(httpPost);
+ response = extractResponseAndClose(status);
+ assertEquals(ERR403, response);
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertFalse(ourHitMethod);
+
+ ourHitMethod = false;
+ httpPost = new HttpPut("http://localhost:" + ourPort + "/Patient?foo=bar");
+ httpPost.setEntity(createFhirResourceEntity(createPatient(99)));
+ status = ourClient.execute(httpPost);
+ response = extractResponseAndClose(status);
+ assertEquals(ERR403, response);
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertFalse(ourHitMethod);
+
+ ourHitMethod = false;
+ httpPost = new HttpPut("http://localhost:" + ourPort + "/Observation/10");
+ httpPost.setEntity(createFhirResourceEntity(createObservation(10, "Patient/1")));
+ status = ourClient.execute(httpPost);
+ extractResponseAndClose(status);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ ourHitMethod = false;
+ httpPost = new HttpPut("http://localhost:" + ourPort + "/Observation/10");
+ httpPost.setEntity(createFhirResourceEntity(createObservation(10, "Patient/2")));
+ status = ourClient.execute(httpPost);
+ response = extractResponseAndClose(status);
+ assertEquals(ERR403, response);
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertFalse(ourHitMethod);
+ }
+
+ @Test
+ public void testWriteByCompartmentUpdateConditionalResolvesToInvalid() throws Exception {
+ ourConditionalCreateId = "1123";
+
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("Rule 1").write().resourcesOfType(Patient.class).inCompartment("Patient", new IdType("Patient/1")).andThen()
+ .allow("Rule 2").write().resourcesOfType(Observation.class).inCompartment("Patient", new IdType("Patient/1")).andThen()
+ .allow("Rule 3").updateConditional().resourcesOfType(Patient.class)
+ .build();
+ }
+ });
+
+ HttpEntityEnclosingRequestBase httpPost;
+ HttpResponse status;
+ String response;
+
+ ourHitMethod = false;
+ httpPost = new HttpPut("http://localhost:" + ourPort + "/Patient?foo=bar");
+ httpPost.setEntity(createFhirResourceEntity(createPatient(null)));
+ status = ourClient.execute(httpPost);
+ response = extractResponseAndClose(status);
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertEquals(ERR403, response);
+ assertTrue(ourHitMethod);
+
+ }
+
+ @Test
+ public void testWriteByCompartmentUpdateConditionalResolvesToValid() throws Exception {
+ ourConditionalCreateId = "1";
+
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("Rule 1").write().resourcesOfType(Patient.class).inCompartment("Patient", new IdType("Patient/1")).andThen()
+ .allow("Rule 2").write().resourcesOfType(Observation.class).inCompartment("Patient", new IdType("Patient/1")).andThen()
+ .allow("Rule 3").updateConditional().resourcesOfType(Patient.class)
+ .build();
+ }
+ });
+
+ HttpEntityEnclosingRequestBase httpPost;
+ HttpResponse status;
+ String response;
+
+ ourHitMethod = false;
+ httpPost = new HttpPut("http://localhost:" + ourPort + "/Patient?foo=bar");
+ httpPost.setEntity(createFhirResourceEntity(createPatient(null)));
+ status = ourClient.execute(httpPost);
+ response = extractResponseAndClose(status);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ ourHitMethod = false;
+ httpPost = new HttpPut("http://localhost:" + ourPort + "/Observation?foo=bar");
+ httpPost.setEntity(createFhirResourceEntity(createObservation(null, "Patient/12")));
+ status = ourClient.execute(httpPost);
+ response = extractResponseAndClose(status);
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertEquals(ERR403, response);
+ assertFalse(ourHitMethod);
+
+ }
+
+ @Test
+ public void testWriteByCompartmentUpdateConditionalResolvesToValidAllTypes() throws Exception {
+ ourConditionalCreateId = "1";
+
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("Rule 1").write().resourcesOfType(Patient.class).inCompartment("Patient", new IdType("Patient/1")).andThen()
+ .allow("Rule 2").write().resourcesOfType(Observation.class).inCompartment("Patient", new IdType("Patient/1")).andThen()
+ .allow("Rule 3").updateConditional().allResources()
+ .build();
+ }
+ });
+
+ HttpEntityEnclosingRequestBase httpPost;
+ HttpResponse status;
+ String response;
+
+ ourHitMethod = false;
+ httpPost = new HttpPut("http://localhost:" + ourPort + "/Patient?foo=bar");
+ httpPost.setEntity(createFhirResourceEntity(createPatient(null)));
+ status = ourClient.execute(httpPost);
+ response = extractResponseAndClose(status);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ ourHitMethod = false;
+ httpPost = new HttpPut("http://localhost:" + ourPort + "/Observation?foo=bar");
+ httpPost.setEntity(createFhirResourceEntity(createObservation(null, "Patient/12")));
+ status = ourClient.execute(httpPost);
+ response = extractResponseAndClose(status);
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertEquals(ERR403, response);
+ assertTrue(ourHitMethod);
+
+ }
+
+ @Test
+ public void testInvalidInstanceIds() throws Exception {
+ try {
+ new RuleBuilder().allow("Rule 1").write().instance((String) null);
+ fail();
+ } catch (NullPointerException e) {
+ assertEquals("theId must not be null or empty", e.getMessage());
+ }
+ try {
+ new RuleBuilder().allow("Rule 1").write().instance("");
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertEquals("theId must not be null or empty", e.getMessage());
+ }
+ try {
+ new RuleBuilder().allow("Rule 1").write().instance("Observation/");
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertEquals("theId must contain an ID part", e.getMessage());
+ }
+ try {
+ new RuleBuilder().allow("Rule 1").write().instance(new IdType());
+ fail();
+ } catch (NullPointerException e) {
+ assertEquals("theId.getValue() must not be null or empty", e.getMessage());
+ }
+ try {
+ new RuleBuilder().allow("Rule 1").write().instance(new IdType(""));
+ fail();
+ } catch (NullPointerException e) {
+ assertEquals("theId.getValue() must not be null or empty", e.getMessage());
+ }
+ try {
+ new RuleBuilder().allow("Rule 1").write().instance(new IdType("Observation", (String) null));
+ fail();
+ } catch (NullPointerException e) {
+ assertEquals("theId must contain an ID part", e.getMessage());
+ }
+ }
+
+ @Test
+ public void testWritePatchByInstance() throws Exception {
+ ourConditionalCreateId = "1";
+
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("Rule 1").write().instance("Patient/900").andThen()
+ .build();
+ }
+ });
+
+ HttpEntityEnclosingRequestBase httpPost;
+ HttpResponse status;
+ String response;
+
+ String input = "[ { \"op\": \"replace\", \"path\": \"/gender\", \"value\": \"male\" } ]";
+
+ ourHitMethod = false;
+ httpPost = new HttpPatch("http://localhost:" + ourPort + "/Patient/900");
+ httpPost.setEntity(new StringEntity(input, ContentType.parse("application/json-patch+json")));
+ status = ourClient.execute(httpPost);
+ response = extractResponseAndClose(status);
+ assertEquals(204, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ ourHitMethod = false;
+ httpPost = new HttpPatch("http://localhost:" + ourPort + "/Patient/999");
+ httpPost.setEntity(new StringEntity(input, ContentType.parse("application/json-patch+json")));
+ status = ourClient.execute(httpPost);
+ response = extractResponseAndClose(status);
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertFalse(ourHitMethod);
+ }
+
+ @Test
+ public void testWriteByInstance() throws Exception {
+ ourConditionalCreateId = "1";
+
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("Rule 1").write().instance("Observation/900").andThen()
+ .allow("Rule 1").write().instance("901").andThen()
+ .build();
+ }
+ });
+
+ HttpEntityEnclosingRequestBase httpPost;
+ HttpResponse status;
+ String response;
+
+ ourHitMethod = false;
+ httpPost = new HttpPut("http://localhost:" + ourPort + "/Observation/900");
+ httpPost.setEntity(createFhirResourceEntity(createObservation(900, "Patient/12")));
+ status = ourClient.execute(httpPost);
+ response = extractResponseAndClose(status);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ ourHitMethod = false;
+ httpPost = new HttpPut("http://localhost:" + ourPort + "/Observation/901");
+ httpPost.setEntity(createFhirResourceEntity(createObservation(901, "Patient/12")));
+ status = ourClient.execute(httpPost);
+ response = extractResponseAndClose(status);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ ourHitMethod = false;
+ httpPost = new HttpPost("http://localhost:" + ourPort + "/Observation");
+ httpPost.setEntity(createFhirResourceEntity(createObservation(null, "Patient/900")));
+ status = ourClient.execute(httpPost);
+ response = extractResponseAndClose(status);
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertEquals(ERR403, response);
+ assertFalse(ourHitMethod);
+
+ ourHitMethod = false;
+ httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
+ httpPost.setEntity(createFhirResourceEntity(createPatient(null)));
+ status = ourClient.execute(httpPost);
+ response = extractResponseAndClose(status);
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertEquals(ERR403, response);
+ assertFalse(ourHitMethod);
+
+ }
+
+ @Test
+ public void testReadByInstance() throws Exception {
+ ourConditionalCreateId = "1";
+
+ ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
+ @Override
+ public List buildRuleList(RequestDetails theRequestDetails) {
+ return new RuleBuilder()
+ .allow("Rule 1").read().instance("Observation/900").andThen()
+ .allow("Rule 1").read().instance("901").andThen()
+ .build();
+ }
+ });
+
+ HttpResponse status;
+ String response;
+ HttpGet httpGet;
+
+ ourReturn = Collections.singletonList(createObservation(900, "Patient/1"));
+ ourHitMethod = false;
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Observation/900");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ ourReturn = Collections.singletonList(createPatient(901));
+ ourHitMethod = false;
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/901");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ assertEquals(200, status.getStatusLine().getStatusCode());
+ assertTrue(ourHitMethod);
+
+ ourReturn = Collections.singletonList(createPatient(1));
+ ourHitMethod = false;
+ httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1?_format=json");
+ status = ourClient.execute(httpGet);
+ response = extractResponseAndClose(status);
+ assertEquals(403, status.getStatusLine().getStatusCode());
+ assertEquals(ERR403, response);
+ assertFalse(ourHitMethod);
+
+ }
+
+ @AfterClass
+ public static void afterClassClearContext() throws Exception {
+ ourServer.stop();
+ TestUtil.clearAllStaticFieldsForUnitTest();
+ }
+
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+
+ ourPort = PortUtil.findFreePort();
+ ourServer = new Server(ourPort);
+
+ DummyPatientResourceProvider patProvider = new DummyPatientResourceProvider();
+ DummyObservationResourceProvider obsProv = new DummyObservationResourceProvider();
+ DummyEncounterResourceProvider encProv = new DummyEncounterResourceProvider();
+ DummyCarePlanResourceProvider cpProv = new DummyCarePlanResourceProvider();
+ PlainProvider plainProvider = new PlainProvider();
+
+ ServletHandler proxyHandler = new ServletHandler();
+ ourServlet = new RestfulServer(ourCtx);
+ ourServlet.setFhirContext(ourCtx);
+ ourServlet.setResourceProviders(patProvider, obsProv, encProv, cpProv);
+ ourServlet.setPlainProviders(plainProvider);
+ ourServlet.setPagingProvider(new FifoMemoryPagingProvider(100));
+ ServletHolder servletHolder = new ServletHolder(ourServlet);
+ 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 DummyCarePlanResourceProvider implements IResourceProvider {
+
+ @Override
+ public Class extends IBaseResource> getResourceType() {
+ return CarePlan.class;
+ }
+
+ @Read(version = true)
+ public CarePlan read(@IdParam IdType theId) {
+ ourHitMethod = true;
+ return (CarePlan) ourReturn.get(0);
+ }
+
+ @Search()
+ public List search() {
+ ourHitMethod = true;
+ return ourReturn;
+ }
+ }
+
+ public static class DummyEncounterResourceProvider implements IResourceProvider {
+
+ @Operation(name = "everything", idempotent = true)
+ public Bundle everything(@IdParam IdType theId) {
+ ourHitMethod = true;
+ Bundle retVal = new Bundle();
+ for (Resource next : ourReturn) {
+ retVal.addEntry().setResource(next);
+ }
+ return retVal;
+ }
+
+ @Override
+ public Class extends IBaseResource> getResourceType() {
+ return Encounter.class;
+ }
+ }
+
+ public static class DummyObservationResourceProvider implements IResourceProvider {
+
+ @Create()
+ public MethodOutcome create(@ResourceParam Observation theResource, @ConditionalUrlParam String theConditionalUrl) {
+ ourHitMethod = true;
+ theResource.setId("Observation/1/_history/1");
+ MethodOutcome retVal = new MethodOutcome();
+ retVal.setCreated(true);
+ retVal.setResource(theResource);
+ return retVal;
+ }
+
+ @Delete()
+ public MethodOutcome delete(@IdParam IdType theId) {
+ ourHitMethod = true;
+ MethodOutcome retVal = new MethodOutcome();
+ return retVal;
+ }
+
+ @Override
+ public Class extends IBaseResource> getResourceType() {
+ return Observation.class;
+ }
+
+ @Operation(name = "opName", idempotent = true)
+ public Parameters operation() {
+ ourHitMethod = true;
+ return (Parameters) new Parameters().setId("1");
+ }
+
+ @Operation(name = "opName", idempotent = true)
+ public Parameters operation(@IdParam IdType theId) {
+ ourHitMethod = true;
+ return (Parameters) new Parameters().setId("1");
+ }
+
+ @Read(version = true)
+ public Observation read(@IdParam IdType theId) {
+ ourHitMethod = true;
+ return (Observation) ourReturn.get(0);
+ }
+
+ @Search()
+ public List search() {
+ ourHitMethod = true;
+ return ourReturn;
+ }
+
+ @Update()
+ public MethodOutcome update(@IdParam IdType theId, @ResourceParam Observation theResource, @ConditionalUrlParam String theConditionalUrl, RequestDetails theRequestDetails) {
+ ourHitMethod = true;
+
+ if (isNotBlank(theConditionalUrl)) {
+ IdType actual = new IdType("Observation", ourConditionalCreateId);
+ ActionRequestDetails subRequest = new ActionRequestDetails(theRequestDetails, actual);
+ subRequest.notifyIncomingRequestPreHandled(RestOperationTypeEnum.UPDATE);
+ theResource.setId(actual);
+ } else {
+ ActionRequestDetails subRequest = new ActionRequestDetails(theRequestDetails, theResource);
+ subRequest.notifyIncomingRequestPreHandled(RestOperationTypeEnum.UPDATE);
+ theResource.setId(theId.withVersion("2"));
+ }
+
+ MethodOutcome retVal = new MethodOutcome();
+ retVal.setResource(theResource);
+ return retVal;
+ }
+
+ }
+
+ public static class DummyPatientResourceProvider implements IResourceProvider {
+
+ @Create()
+ public MethodOutcome create(@ResourceParam Patient theResource, @ConditionalUrlParam String theConditionalUrl, RequestDetails theRequestDetails) {
+
+ if (isNotBlank(theConditionalUrl)) {
+ IdType actual = new IdType("Patient", ourConditionalCreateId);
+ ActionRequestDetails subRequest = new ActionRequestDetails(theRequestDetails, actual);
+ subRequest.notifyIncomingRequestPreHandled(RestOperationTypeEnum.CREATE);
+ } else {
+ ActionRequestDetails subRequest = new ActionRequestDetails(theRequestDetails, theResource);
+ subRequest.notifyIncomingRequestPreHandled(RestOperationTypeEnum.CREATE);
+ }
+
+ ourHitMethod = true;
+ theResource.setId("Patient/1/_history/1");
+ MethodOutcome retVal = new MethodOutcome();
+ retVal.setCreated(true);
+ retVal.setResource(theResource);
+ return retVal;
+ }
+
+ @Delete()
+ public MethodOutcome delete(IRequestOperationCallback theRequestOperationCallback, @IdParam IdType theId, @ConditionalUrlParam String theConditionalUrl, RequestDetails theRequestDetails) {
+ ourHitMethod = true;
+ for (IBaseResource next : ourReturn) {
+ theRequestOperationCallback.resourceDeleted(next);
+ }
+ MethodOutcome retVal = new MethodOutcome();
+ return retVal;
+ }
+
+ @Operation(name = "everything", idempotent = true)
+ public Bundle everything(@IdParam IdType theId) {
+ ourHitMethod = true;
+ Bundle retVal = new Bundle();
+ for (Resource next : ourReturn) {
+ retVal.addEntry().setResource(next);
+ }
+ return retVal;
+ }
+
+ @Override
+ public Class extends IBaseResource> getResourceType() {
+ return Patient.class;
+ }
+
+ @History()
+ public List history() {
+ ourHitMethod = true;
+ return (ourReturn);
+ }
+
+ @History()
+ public List history(@IdParam IdType theId) {
+ ourHitMethod = true;
+ return (ourReturn);
+ }
+
+ @Operation(name = "opName", idempotent = true)
+ public Parameters operation() {
+ ourHitMethod = true;
+ return (Parameters) new Parameters().setId("1");
+ }
+
+ @Operation(name = "opName", idempotent = true)
+ public Parameters operation(@IdParam IdType theId) {
+ ourHitMethod = true;
+ return (Parameters) new Parameters().setId("1");
+ }
+
+ @Operation(name = "opName2", idempotent = true)
+ public Parameters operation2(@IdParam IdType theId) {
+ ourHitMethod = true;
+ return (Parameters) new Parameters().setId("1");
+ }
+
+ @Operation(name = "opName2", idempotent = true)
+ public Parameters operation2() {
+ ourHitMethod = true;
+ return (Parameters) new Parameters().setId("1");
+ }
+
+ @Read(version = true)
+ public Patient read(@IdParam IdType theId) {
+ ourHitMethod = true;
+ return (Patient) ourReturn.get(0);
+ }
+
+ @Search()
+ public List search() {
+ ourHitMethod = true;
+ return ourReturn;
+ }
+
+ @Update()
+ public MethodOutcome update(@IdParam IdType theId, @ResourceParam Patient theResource, @ConditionalUrlParam String theConditionalUrl, RequestDetails theRequestDetails) {
+ ourHitMethod = true;
+
+ if (isNotBlank(theConditionalUrl)) {
+ IdType actual = new IdType("Patient", ourConditionalCreateId);
+ ActionRequestDetails subRequest = new ActionRequestDetails(theRequestDetails, actual);
+ subRequest.notifyIncomingRequestPreHandled(RestOperationTypeEnum.UPDATE);
+ theResource.setId(actual);
+ } else {
+ ActionRequestDetails subRequest = new ActionRequestDetails(theRequestDetails, theResource);
+ subRequest.notifyIncomingRequestPreHandled(RestOperationTypeEnum.UPDATE);
+ theResource.setId(theId.withVersion("2"));
+ }
+
+ MethodOutcome retVal = new MethodOutcome();
+ retVal.setResource(theResource);
+ return retVal;
+ }
+
+ @Patch()
+ public MethodOutcome patch(@IdParam IdType theId, @ResourceParam String theResource, PatchTypeEnum thePatchType) {
+ ourHitMethod = true;
+
+ MethodOutcome retVal = new MethodOutcome();
+ return retVal;
+ }
+
+ @Validate
+ public MethodOutcome validate(@ResourceParam Patient theResource, @IdParam IdType theId, @ResourceParam String theRawResource, @ResourceParam EncodingEnum theEncoding,
+ @Validate.Mode ValidationModeEnum theMode, @Validate.Profile String theProfile, RequestDetails theRequestDetails) {
+ ourHitMethod = true;
+ OperationOutcome oo = new OperationOutcome();
+ oo.addIssue().setDiagnostics("OK");
+ return new MethodOutcome(oo);
+ }
+
+ @Validate
+ public MethodOutcome validate(@ResourceParam Patient theResource, @ResourceParam String theRawResource, @ResourceParam EncodingEnum theEncoding, @Validate.Mode ValidationModeEnum theMode,
+ @Validate.Profile String theProfile, RequestDetails theRequestDetails) {
+ ourHitMethod = true;
+ OperationOutcome oo = new OperationOutcome();
+ oo.addIssue().setDiagnostics("OK");
+ return new MethodOutcome(oo);
+ }
+
+ }
+
+ public static class PlainProvider {
+
+ @History()
+ public List history() {
+ ourHitMethod = true;
+ return (ourReturn);
+ }
+
+ @Operation(name = "opName", idempotent = true)
+ public Parameters operation() {
+ ourHitMethod = true;
+ return (Parameters) new Parameters().setId("1");
+ }
+
+ @Transaction()
+ public Bundle search(@TransactionParam Bundle theInput) {
+ ourHitMethod = true;
+ return (Bundle) ourReturn.get(0);
+ }
+
+ }
+
+}