diff --git a/lib/ConsentEnforcementService.js b/lib/ConsentEnforcementService.js index f59e47a..44471cb 100644 --- a/lib/ConsentEnforcementService.js +++ b/lib/ConsentEnforcementService.js @@ -1,11 +1,10 @@ -const _ = require("lodash"); - const logger = require("./logger"); const ConsentDecision = require("./ConsentDecision"); const PatientDiscovery = require("./PatientDiscovery"); const RedactionService = require("./RedactionService"); const AuthUtils = require("./AuthUtils"); +const { label } = require("./LabelingClient"); const UNPROTECTED_RESOURCE_TYPES = ( process.env.UNPROTECTED_RESOURCE_TYPES || "" @@ -29,7 +28,7 @@ async function checkConsent(req, response) { } async function checkConsentForBundle(req, response) { - const newResponse = _.cloneDeep(response); + const newResponse = await label(response); delete newResponse.total; //total is optional and we cannot know what resources are redacted. const patientRefs = response.entry @@ -81,7 +80,8 @@ const releasePermitted = (consentDecision, resource) => !RedactionService.redactResource(consentDecision.obligations, resource); async function checkConsentForResource(req, response) { - const patientRef = PatientDiscovery.patientReference(response); + const newResponse = await label(response); + const patientRef = PatientDiscovery.patientReference(newResponse); if (!patientRef) { throw { error: "consent_deny" @@ -98,8 +98,8 @@ async function checkConsentForResource(req, response) { ); logger.info(`consent decision: ${JSON.stringify(consentDecision)}`); - if (releasePermitted(consentDecision, response)) { - return response; + if (releasePermitted(consentDecision, newResponse)) { + return newResponse; } else { logger.warn(`consent denied acccess to ${req.path}`); throw { diff --git a/lib/ErrorUtils.js b/lib/ErrorUtils.js index 75e2704..6926aed 100644 --- a/lib/ErrorUtils.js +++ b/lib/ErrorUtils.js @@ -5,11 +5,11 @@ function commonExceptions(e) { return e.error === "consent_deny" ? { - status: 403, + status: 404, body: { - message: "forbidden", - error: "forbidden", - status: 403 + message: "resource not found", + error: "not found", + status: 404 } } : e.error === "token_error" diff --git a/lib/LabelingClient.js b/lib/LabelingClient.js new file mode 100644 index 0000000..da19fda --- /dev/null +++ b/lib/LabelingClient.js @@ -0,0 +1,25 @@ +const request = require("superagent"); +const CDS_HOST = process.env.CDS_HOST; +const SLS_ENDPOINT = `${CDS_HOST}/sls`; + +async function label(resource) { + try { + const response = await request + .post(SLS_ENDPOINT) + .set("Accept", "application/json") + .send(resource); + + return response.body; + } catch (e) { + console.log(e) + logger.warn(`SLS invocation failed: ${e}`); + throw { + error: "internal_error", + status: 500 + }; + } +} + +module.exports = { + label +}; diff --git a/tests/consent-enforcement.test.js b/tests/consent-enforcement.test.js index e8f9d77..49c91d8 100644 --- a/tests/consent-enforcement.test.js +++ b/tests/consent-enforcement.test.js @@ -11,6 +11,7 @@ const FHIR_SERVER_BASE = const CDS_HOST = process.env.CDS_HOST || "https://mock-cds"; const CDS_ENDPOINT = "/cds-services/patient-consent-consult"; +const SLS_ENDPOINT = "/sls"; const CDS_PERMIT_RESPONSE = { cards: [ @@ -155,6 +156,7 @@ it("should fetch a resource if consent permits", async () => { MOCK_FHIR_SERVER.get("/Patient/1").reply(200, patient); MOCK_FHIR_SERVER.get("/MedicationStatement/1").reply(200, medication); + MOCK_CDS.post(SLS_ENDPOINT).reply(200, medication); MOCK_CDS.post(CDS_ENDPOINT).reply(200, CDS_PERMIT_RESPONSE); const res = await request(app) @@ -166,13 +168,14 @@ it("should fetch a resource if consent permits", async () => { expect(res.body).toEqual(medication); }); -it("should send 403 if consent denies", async () => { +it("should send 404 if consent denies", async () => { expect.assertions(1); const patient = require("./fixtures/patient.json"); const medication = require("./fixtures/medication-statement.json"); MOCK_FHIR_SERVER.get("/Patient/1").reply(200, patient); MOCK_FHIR_SERVER.get("/MedicationStatement/1").reply(200, medication); + MOCK_CDS.post(SLS_ENDPOINT).reply(200, medication); MOCK_CDS.post(CDS_ENDPOINT).reply(200, CDS_DENY_RESPONSE); const res = await request(app) @@ -180,16 +183,17 @@ it("should send 403 if consent denies", async () => { .set("content-type", "application/json") .set("Authorization", `Bearer ${JWT}`); - expect(res.status).toEqual(403); + expect(res.status).toEqual(404); }); -it("should send 403 if consent obligation requires redaction", async () => { +it("should send 404 if consent obligation requires redaction", async () => { expect.assertions(1); const patient = require("./fixtures/patient.json"); const medication = require("./fixtures/medication-statement.json"); MOCK_FHIR_SERVER.get("/Patient/1").reply(200, patient); MOCK_FHIR_SERVER.get("/MedicationStatement/1").reply(200, medication); + MOCK_CDS.post(SLS_ENDPOINT).reply(200, medication); MOCK_CDS.post(CDS_ENDPOINT).reply(200, CDS_PERMIT_RESPONSE); const res = await request(app) @@ -197,7 +201,7 @@ it("should send 403 if consent obligation requires redaction", async () => { .set("content-type", "application/json") .set("Authorization", `Bearer ${JWT}`); - expect(res.status).toEqual(403); + expect(res.status).toEqual(404); }); it("should fetch a bundle and return only the resources which the consent permits and not to be redacted", async () => { @@ -209,6 +213,7 @@ it("should fetch a bundle and return only the resources which the consent permit MOCK_FHIR_SERVER.get("/Patient/2").reply(200, patient2); MOCK_FHIR_SERVER.get("/MedicationStatement").reply(200, medicationBundle); + MOCK_CDS.post(SLS_ENDPOINT).reply(200, medicationBundle); MOCK_CDS.post(CDS_ENDPOINT).reply(200, CDS_PERMIT_RESPONSE); MOCK_CDS.post(CDS_ENDPOINT).reply(200, CDS_DENY_RESPONSE); @@ -231,6 +236,7 @@ it("should fetch a bundle and return only the resources which the consent permit MOCK_FHIR_SERVER.get("/Patient/2").reply(200, patient2); MOCK_FHIR_SERVER.get("/MedicationStatement").reply(200, medicationBundle); + MOCK_CDS.post(SLS_ENDPOINT).reply(200, medicationBundle); MOCK_CDS.post(CDS_ENDPOINT).reply( 200, CDS_PERMIT_RESPONSE_CONTENT_CLASS_OBLIGATION