Merge branch 'master' into 4941-performing-javascript-reject-operation-during-consent-validation-does-not-return-403

This commit is contained in:
souradeepsaha 2023-05-26 10:19:27 -04:00
commit fdf748ba9f
5 changed files with 54 additions and 0 deletions

View File

@ -58,6 +58,7 @@ public class ConsentInterceptors {
Observation obs = (Observation)theResource; Observation obs = (Observation)theResource;
if (obs.getCategoryFirstRep().hasCoding("http://hl7.org/fhir/codesystem-observation-category.html", "laboratory")) { if (obs.getCategoryFirstRep().hasCoding("http://hl7.org/fhir/codesystem-observation-category.html", "laboratory")) {
return ConsentOutcome.REJECT; return ConsentOutcome.REJECT;
//return ConsentOutcome.FORBID;
} }
} }

View File

@ -165,6 +165,7 @@ public class ConsentInterceptor {
Validate.notNull(outcome, "Consent service returned null outcome"); Validate.notNull(outcome, "Consent service returned null outcome");
switch (outcome.getStatus()) { switch (outcome.getStatus()) {
case FORBID:
case REJECT: case REJECT:
throw toForbiddenOperationException(outcome); throw toForbiddenOperationException(outcome);
case PROCEED: case PROCEED:
@ -243,9 +244,12 @@ public class ConsentInterceptor {
skipSubsequentServices = true; skipSubsequentServices = true;
break; break;
case REJECT: case REJECT:
authorizedResources.put(nextResource, Boolean.FALSE);
thePreResourceAccessDetails.setDontReturnResourceAtIndex(resourceIdx); thePreResourceAccessDetails.setDontReturnResourceAtIndex(resourceIdx);
skipSubsequentServices = true; skipSubsequentServices = true;
break; break;
case FORBID:
throw toForbiddenOperationException(outcome);
} }
if (skipSubsequentServices) { if (skipSubsequentServices) {
@ -295,6 +299,7 @@ public class ConsentInterceptor {
thePreResourceShowDetails.setResource(i, newResource); thePreResourceShowDetails.setResource(i, newResource);
} }
continue; continue;
case FORBID:
case REJECT: case REJECT:
if (nextOutcome.getOperationOutcome() != null) { if (nextOutcome.getOperationOutcome() != null) {
IBaseOperationOutcome newOperationOutcome = nextOutcome.getOperationOutcome(); IBaseOperationOutcome newOperationOutcome = nextOutcome.getOperationOutcome();
@ -345,6 +350,7 @@ public class ConsentInterceptor {
} }
switch (outcome.getStatus()) { switch (outcome.getStatus()) {
case FORBID:
case REJECT: case REJECT:
if (outcome.getOperationOutcome() != null) { if (outcome.getOperationOutcome() != null) {
theResource.setResponseResource(outcome.getOperationOutcome()); theResource.setResponseResource(outcome.getOperationOutcome());
@ -393,6 +399,7 @@ public class ConsentInterceptor {
boolean shouldReplaceResource = false; boolean shouldReplaceResource = false;
switch (childOutcome.getStatus()) { switch (childOutcome.getStatus()) {
case FORBID:
case REJECT: case REJECT:
replacementResource = childOutcome.getOperationOutcome(); replacementResource = childOutcome.getOperationOutcome();
shouldReplaceResource = true; shouldReplaceResource = true;

View File

@ -40,4 +40,10 @@ public enum ConsentOperationStatusEnum {
*/ */
AUTHORIZED, AUTHORIZED,
/**
* The requested operation cannot proceed, and an operation outcome suitable for
* the user is available
*/
FORBID
} }

View File

@ -38,6 +38,11 @@ public class ConsentOutcome {
*/ */
public static final ConsentOutcome AUTHORIZED = new ConsentOutcome(ConsentOperationStatusEnum.AUTHORIZED); public static final ConsentOutcome AUTHORIZED = new ConsentOutcome(ConsentOperationStatusEnum.AUTHORIZED);
/**
* Convenience constant containing <code>new ConsentOutcome(ConsentOperationStatusEnum.FORBID)</code>
*/
public static final ConsentOutcome FORBID = new ConsentOutcome(ConsentOperationStatusEnum.FORBID);
private final ConsentOperationStatusEnum myStatus; private final ConsentOperationStatusEnum myStatus;
private final IBaseOperationOutcome myOperationOutcome; private final IBaseOperationOutcome myOperationOutcome;
private final IBaseResource myResource; private final IBaseResource myResource;

View File

@ -28,8 +28,11 @@ import com.google.common.base.Charsets;
import com.helger.commons.collection.iterate.EmptyEnumeration; import com.helger.commons.collection.iterate.EmptyEnumeration;
import org.apache.commons.collections4.iterators.IteratorEnumeration; import org.apache.commons.collections4.iterators.IteratorEnumeration;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.http.HttpHeaders;
import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.StringEntity;
import org.hl7.fhir.instance.model.api.IBaseParameters; import org.hl7.fhir.instance.model.api.IBaseParameters;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Bundle;
@ -153,6 +156,38 @@ public class ConsentInterceptorTest {
verify(myConsentSvc, timeout(2000).times(0)).completeOperationFailure(any(), any(), any()); verify(myConsentSvc, timeout(2000).times(0)).completeOperationFailure(any(), any(), any());
} }
@Test
public void testConsentCanSeeResourceForbid() throws IOException {
Patient patientA = new Patient();
patientA.setId("PT-1-0");
patientA.setActive(true);
patientA.addName().setFamily("FAMILY").addGiven("GIVEN");
patientA.addIdentifier().setSystem("SYSTEM").setValue("VALUEA");
ourPatientProvider.store(patientA);
when(myConsentSvc.startOperation(any(), any())).thenReturn(ConsentOutcome.PROCEED);
when(myConsentSvc.canSeeResource(any(), any(), any())).thenReturn(ConsentOutcome.FORBID);
HttpPut httpPut = new HttpPut("http://localhost:" + myPort + "/Patient/PT-1-0");
httpPut.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
httpPut.setEntity(new StringEntity("{\"resourceType\": \"Patient\",\"id\": \"PT-1-0\",\"text\": {\"status\": \"generated\",\"div\": \"<div><p>A valid patient resource for testing purposes</p></div>\"},\"gender\": \"male\"}"));
try (CloseableHttpResponse status = myClient.execute(httpPut)) {
String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8);
System.out.println("here");
ourLog.info("Response: {}", responseContent);
assertEquals(403, status.getStatusLine().getStatusCode());
//String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8);
System.out.println("here");
ourLog.info("Response: {}", responseContent);
}
verify(myConsentSvc, timeout(2000).times(1)).completeOperationSuccess(any(), any());
verify(myConsentSvc, timeout(2000).times(0)).completeOperationFailure(any(), any(), any());
}
@Test @Test
public void testTotalModeIgnoredForConsentQueries() throws IOException { public void testTotalModeIgnoredForConsentQueries() throws IOException {
Patient patientA = new Patient(); Patient patientA = new Patient();