Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

3400 bulk export rules incorrectly applied to group and patient exports #3403

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
type: fix
issue: 3400
title: "User was permitted to bulk export all groups/patients when they were unauthorized. This issue has been fixed."
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ public AuthorizationInterceptor.Verdict applyRule(RestOperationTypeEnum theOpera
String actualGroupId = options.getGroupId().toUnqualifiedVersionless().getValue();
if (Objects.equals(expectedGroupId, actualGroupId)) {
return newVerdict(theOperation, theRequestDetails, theInputResource, theInputResourceId, theOutputResource);
} else {
return new AuthorizationInterceptor.Verdict(PolicyEnum.DENY,this);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ca.uhn.fhir.rest.server.interceptor.auth;

import ca.uhn.fhir.interceptor.api.Pointcut;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.api.server.bulk.BulkDataExportOptions;
Expand All @@ -19,7 +20,8 @@

@ExtendWith(MockitoExtension.class)
public class RuleBulkExportImplTest {

private RestOperationTypeEnum myOperation = RestOperationTypeEnum.EXTENDED_OPERATION_SERVER;
private Pointcut myPointcut = Pointcut.STORAGE_INITIATE_BULK_EXPORT;
@Mock
private RequestDetails myRequestDetails;
@Mock
Expand All @@ -30,8 +32,6 @@ public class RuleBulkExportImplTest {
@Test
public void testDenyBulkRequestWithInvalidResourcesTypes() {
RuleBulkExportImpl myRule = new RuleBulkExportImpl("a");
RestOperationTypeEnum myOperation = RestOperationTypeEnum.EXTENDED_OPERATION_SERVER;
Pointcut myPointcut = Pointcut.STORAGE_INITIATE_BULK_EXPORT;

Set<String> myTypes = new HashSet<>();
myTypes.add("Patient");
Expand All @@ -43,6 +43,7 @@ public void testDenyBulkRequestWithInvalidResourcesTypes() {

BulkDataExportOptions options = new BulkDataExportOptions();
options.setResourceTypes(myWantTypes);

when(myRequestDetails.getAttribute(any())).thenReturn(options);

AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut);
Expand All @@ -52,8 +53,6 @@ public void testDenyBulkRequestWithInvalidResourcesTypes() {
@Test
public void testBulkRequestWithValidResourcesTypes() {
RuleBulkExportImpl myRule = new RuleBulkExportImpl("a");
RestOperationTypeEnum myOperation = RestOperationTypeEnum.EXTENDED_OPERATION_SERVER;
Pointcut myPointcut = Pointcut.STORAGE_INITIATE_BULK_EXPORT;

Set<String> myTypes = new HashSet<>();
myTypes.add("Patient");
Expand All @@ -66,10 +65,43 @@ public void testBulkRequestWithValidResourcesTypes() {

BulkDataExportOptions options = new BulkDataExportOptions();
options.setResourceTypes(myWantTypes);

when(myRequestDetails.getAttribute(any())).thenReturn(options);

AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut);
assertNull(verdict);
}

}
@Test
public void testDenyBulkRequestWithInvalidGroupId() {
oliviayou marked this conversation as resolved.
Show resolved Hide resolved
RuleBulkExportImpl myRule = new RuleBulkExportImpl("a");
myRule.setAppliesToGroupExportOnGroup("invalid group");
myRule.setMode(PolicyEnum.ALLOW);

BulkDataExportOptions options = new BulkDataExportOptions();
options.setExportStyle(BulkDataExportOptions.ExportStyle.GROUP);
options.setGroupId(new IdDt("Group/123"));

when(myRequestDetails.getAttribute(any())).thenReturn(options);

AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut);
assertEquals(PolicyEnum.DENY, verdict.getDecision());
}

@Test
public void testAllowBulkRequestWithValidGroupId() {
RuleBulkExportImpl myRule = new RuleBulkExportImpl("a");
myRule.setAppliesToGroupExportOnGroup("Group/1");
myRule.setMode(PolicyEnum.ALLOW);

BulkDataExportOptions options = new BulkDataExportOptions();
options.setExportStyle(BulkDataExportOptions.ExportStyle.GROUP);
options.setGroupId(new IdDt("Group/1"));

when(myRequestDetails.getAttribute(any())).thenReturn(options);

AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut);
assertEquals(PolicyEnum.ALLOW, verdict.getDecision());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ public void groupExport(
validatePreferAsyncHeader(theRequestDetails);
BulkDataExportOptions bulkDataExportOptions = buildGroupBulkExportOptions(theOutputFormat, theType, theSince, theTypeFilter, theIdParam, theMdm);
validateResourceTypesAllContainPatientSearchParams(bulkDataExportOptions.getResourceTypes());
IBulkDataExportSvc.JobInfo outcome = myBulkDataExportSvc.submitJob(bulkDataExportOptions, shouldUseCache(theRequestDetails), null);
IBulkDataExportSvc.JobInfo outcome = myBulkDataExportSvc.submitJob(bulkDataExportOptions, shouldUseCache(theRequestDetails), theRequestDetails);
writePollingLocationToResponseHeaders(theRequestDetails, outcome);
}

Expand Down Expand Up @@ -158,7 +158,7 @@ public void patientExport(
validatePreferAsyncHeader(theRequestDetails);
BulkDataExportOptions bulkDataExportOptions = buildPatientBulkExportOptions(theOutputFormat, theType, theSince, theTypeFilter);
validateResourceTypesAllContainPatientSearchParams(bulkDataExportOptions.getResourceTypes());
IBulkDataExportSvc.JobInfo outcome = myBulkDataExportSvc.submitJob(bulkDataExportOptions, shouldUseCache(theRequestDetails), null);
IBulkDataExportSvc.JobInfo outcome = myBulkDataExportSvc.submitJob(bulkDataExportOptions, shouldUseCache(theRequestDetails), theRequestDetails);
writePollingLocationToResponseHeaders(theRequestDetails, outcome);
}

Expand Down