diff --git a/fhir-smart/src/main/java/org/linuxforhealth/fhir/smart/AuthzPolicyEnforcementPersistenceInterceptor.java b/fhir-smart/src/main/java/org/linuxforhealth/fhir/smart/AuthzPolicyEnforcementPersistenceInterceptor.java index 66a1b1a6e1f..e9dfe8c8a81 100644 --- a/fhir-smart/src/main/java/org/linuxforhealth/fhir/smart/AuthzPolicyEnforcementPersistenceInterceptor.java +++ b/fhir-smart/src/main/java/org/linuxforhealth/fhir/smart/AuthzPolicyEnforcementPersistenceInterceptor.java @@ -458,6 +458,15 @@ public void beforeDelete(FHIRPersistenceEvent event) throws FHIRPersistenceInter @Override public void beforeUpdate(FHIRPersistenceEvent event) throws FHIRPersistenceInterceptorException { + beforeUpdateOrPatch(event); + } + + @Override + public void beforePatch(FHIRPersistenceEvent event) throws FHIRPersistenceInterceptorException { + beforeUpdateOrPatch(event); + } + + private void beforeUpdateOrPatch(FHIRPersistenceEvent event) throws FHIRPersistenceInterceptorException { DecodedJWT jwt = JWT.decode(getAccessToken()); Set patientIdFromToken = getPatientIdFromToken(jwt); Map> scopesFromToken = getScopesFromToken(jwt); diff --git a/fhir-smart/src/test/java/org/linuxforhealth/fhir/smart/test/AuthzPolicyEnforcementTest.java b/fhir-smart/src/test/java/org/linuxforhealth/fhir/smart/test/AuthzPolicyEnforcementTest.java index a79cfc1565f..a36e2c5856a 100644 --- a/fhir-smart/src/test/java/org/linuxforhealth/fhir/smart/test/AuthzPolicyEnforcementTest.java +++ b/fhir-smart/src/test/java/org/linuxforhealth/fhir/smart/test/AuthzPolicyEnforcementTest.java @@ -202,6 +202,10 @@ public void testCreate(String scopeString, List contextIds, Set contextIds, Set resourceTypesPermittedByScope, Permission permission) { FHIRRequestContext.get().setHttpHeaders(buildRequestHeaders(scopeString, contextIds)); @@ -255,7 +259,8 @@ public void testUpdate(String scopeString, List contextIds, Set contextIds, Set contextIds, Set resourceTypesPermittedByScope, Permission permission) { + FHIRRequestContext.get().setHttpHeaders(buildRequestHeaders(scopeString, contextIds)); + + try { + properties.put(FHIRPersistenceEvent.PROPNAME_RESOURCE_TYPE, "Patient"); + FHIRPersistenceEvent event = new FHIRPersistenceEvent(patient, properties); + event.setPrevFhirResource(patient); + interceptor.beforePatch(event); + assertTrue(shouldSucceed(resourceTypesPermittedByScope, PATIENT, READ_APPROVED, permission) && + shouldSucceed(resourceTypesPermittedByScope, PATIENT, WRITE_APPROVED, permission)); + } catch (FHIRPersistenceInterceptorException e) { + assertFalse(shouldSucceed(resourceTypesPermittedByScope, PATIENT, READ_APPROVED, permission) && + shouldSucceed(resourceTypesPermittedByScope, PATIENT, WRITE_APPROVED, permission)); + } + + try { + properties.put(FHIRPersistenceEvent.PROPNAME_RESOURCE_TYPE, "Observation"); + FHIRPersistenceEvent event = new FHIRPersistenceEvent(observation, properties); + event.setPrevFhirResource(observation); + interceptor.beforePatch(event); + assertTrue(shouldSucceed(resourceTypesPermittedByScope, OBSERVATION, READ_APPROVED, permission) && + shouldSucceed(resourceTypesPermittedByScope, OBSERVATION, WRITE_APPROVED, permission)); + } catch (FHIRPersistenceInterceptorException e) { + assertFalse(shouldSucceed(resourceTypesPermittedByScope, OBSERVATION, READ_APPROVED, permission) && + shouldSucceed(resourceTypesPermittedByScope, OBSERVATION, WRITE_APPROVED, permission)); + } + + try { + properties.put(FHIRPersistenceEvent.PROPNAME_RESOURCE_TYPE, "Condition"); + FHIRPersistenceEvent event = new FHIRPersistenceEvent(condition, properties); + event.setPrevFhirResource(condition); + interceptor.beforePatch(event); + assertTrue(shouldSucceed(resourceTypesPermittedByScope, CONDITION, READ_APPROVED, permission) && + shouldSucceed(resourceTypesPermittedByScope, CONDITION, WRITE_APPROVED, permission)); + } catch (FHIRPersistenceInterceptorException e) { + assertFalse(shouldSucceed(resourceTypesPermittedByScope, CONDITION, READ_APPROVED, permission) && + shouldSucceed(resourceTypesPermittedByScope, CONDITION, WRITE_APPROVED, permission)); } + // Test beforePatch Binary Resource which does not have a securityContext. Should Succeed + try { + properties.put(FHIRPersistenceEvent.PROPNAME_RESOURCE_TYPE, "Binary"); + FHIRPersistenceEvent event = new FHIRPersistenceEvent(binary, properties); + event.setPrevFhirResource(binary); + interceptor.beforePatch(event); + assertTrue(shouldSucceed(resourceTypesPermittedByScope, BINARY, READ_APPROVED, permission) && + shouldSucceed(resourceTypesPermittedByScope, BINARY, WRITE_APPROVED, permission)); + } catch (FHIRPersistenceInterceptorException e) { + assertFalse(shouldSucceed(resourceTypesPermittedByScope, BINARY, READ_APPROVED, permission) && + shouldSucceed(resourceTypesPermittedByScope, BINARY, WRITE_APPROVED, permission)); + } + // Test beforePatch Binary Resource which has a securityContext. + // It should be an exception since securityContext is not supported. + try { + properties.put(FHIRPersistenceEvent.PROPNAME_RESOURCE_TYPE, "Binary"); + FHIRPersistenceEvent event = new FHIRPersistenceEvent(binaryWithSecurityContext, properties); + event.setPrevFhirResource(binaryWithSecurityContext); + interceptor.beforePatch(event); + fail("Did not receive the expected FHIRPersistenceInterceptorException"); + } catch (FHIRPersistenceInterceptorException e) { + if (shouldSucceed(resourceTypesPermittedByScope, BINARY, READ_APPROVED, permission) && + shouldSucceed(resourceTypesPermittedByScope, BINARY, WRITE_APPROVED, permission)) { + assertTrue(e.getMessage().equals("securityContext is not supported for resource type Binary")); + } + // else beforePatch was rejected due to normal fhir-smart behavior (non-securityContext-related) + } } @Test(dataProvider = "scopeStringProvider") @@ -1559,6 +1637,7 @@ private Map> buildRequestHeaders(String scopeString, List resourceTypesPermittedByScope, ResourceType requiredResourceType, List permissionsPermittedByScope, Permission requiredPermission) {