Improve processing of deletes in AuthorizationInterceptor

This commit is contained in:
jamesagnew 2019-06-29 14:40:51 -04:00
parent ccf491b3ae
commit 5c0e54fb86
5 changed files with 40 additions and 13 deletions

View File

@ -159,7 +159,7 @@ public class AuthorizationInterceptor implements IRuleApplier {
case DELETE: case DELETE:
// Delete is a special case // Delete is a special case
return OperationExamineDirection.NONE; return OperationExamineDirection.IN;
case CREATE: case CREATE:
case UPDATE: case UPDATE:

View File

@ -52,19 +52,27 @@ public class RuleImplConditional extends BaseRule implements IAuthRule {
} }
if (theOperation == myOperationType) { if (theOperation == myOperationType) {
if (theRequestDetails.getConditionalUrl(myOperationType) == null) {
return null;
}
switch (myAppliesTo) { switch (myAppliesTo) {
case ALL_RESOURCES: case ALL_RESOURCES:
case INSTANCES: case INSTANCES:
break; break;
case TYPES: case TYPES:
if (myOperationType == RestOperationTypeEnum.DELETE) {
String resourceName = theRequestDetails.getResourceName();
Class<? extends IBaseResource> resourceType = theRequestDetails.getFhirContext().getResourceDefinition(resourceName).getImplementingClass();
if (!myAppliesToTypes.contains(resourceType)) {
return null;
}
} else {
if (theInputResource == null || !myAppliesToTypes.contains(theInputResource.getClass())) { if (theInputResource == null || !myAppliesToTypes.contains(theInputResource.getClass())) {
return null; return null;
} }
break;
} }
break;
if (theRequestDetails.getConditionalUrl(myOperationType) == null) {
return null;
} }
if (getTenantApplicabilityChecker() != null) { if (getTenantApplicabilityChecker() != null) {

View File

@ -13,6 +13,7 @@ import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.rest.server.interceptor.auth.AuthorizationInterceptor.Verdict; import ca.uhn.fhir.rest.server.interceptor.auth.AuthorizationInterceptor.Verdict;
import ca.uhn.fhir.util.BundleUtil; import ca.uhn.fhir.util.BundleUtil;
import ca.uhn.fhir.util.BundleUtil.BundleEntryParts; import ca.uhn.fhir.util.BundleUtil.BundleEntryParts;
import ca.uhn.fhir.util.CollectionUtil;
import ca.uhn.fhir.util.FhirTerser; import ca.uhn.fhir.util.FhirTerser;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -215,6 +216,7 @@ class RuleImplOp extends BaseRule /* implements IAuthRule */ {
return newVerdict(); return newVerdict();
} }
appliesToResource = theInputResource; appliesToResource = theInputResource;
appliesToResourceId = Collections.singleton(theInputResourceId);
} else { } else {
return null; return null;
} }

View File

@ -3033,22 +3033,34 @@ public class AuthorizationInterceptorR4Test {
@Override @Override
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) { public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
return new RuleBuilder() return new RuleBuilder()
.allow("Rule 2").deleteConditional().resourcesOfType(Patient.class) .allow("Rule 2").deleteConditional().resourcesOfType(Patient.class).andThen()
.allow().delete().instance(new IdType("Patient/2")).andThen()
.build(); .build();
} }
}); });
HttpDelete httpDelete; HttpDelete httpDelete;
HttpResponse status; HttpResponse status;
String response;
ourReturn = Collections.singletonList(createPatient(1)); // // Wrong resource
// ourReturn = Collections.singletonList(createPatient(1));
// ourHitMethod = false;
// httpDelete = new HttpDelete("http://localhost:" + ourPort + "/Patient?foo=bar");
// status = ourClient.execute(httpDelete);
// response = extractResponseAndClose(status);
// ourLog.info(response);
// assertEquals(403, status.getStatusLine().getStatusCode());
// assertTrue(ourHitMethod);
// Right resource
ourReturn = Collections.singletonList(createPatient(2));
ourHitMethod = false; ourHitMethod = false;
httpDelete = new HttpDelete("http://localhost:" + ourPort + "/Patient?foo=bar"); httpDelete = new HttpDelete("http://localhost:" + ourPort + "/Patient?foo=bar");
status = ourClient.execute(httpDelete); status = ourClient.execute(httpDelete);
String response = extractResponseAndClose(status); response = extractResponseAndClose(status);
ourLog.info(response); ourLog.info(response);
assertEquals(403, status.getStatusLine().getStatusCode()); assertEquals(204, status.getStatusLine().getStatusCode());
assertTrue(ourHitMethod); assertTrue(ourHitMethod);
} }
@ -3074,7 +3086,7 @@ public class AuthorizationInterceptorR4Test {
status = ourClient.execute(httpDelete); status = ourClient.execute(httpDelete);
extractResponseAndClose(status); extractResponseAndClose(status);
assertEquals(403, status.getStatusLine().getStatusCode()); assertEquals(403, status.getStatusLine().getStatusCode());
assertTrue(ourHitMethod); assertFalse(ourHitMethod);
ourHitMethod = false; ourHitMethod = false;
ourReturn = Collections.singletonList(createPatient(1)); ourReturn = Collections.singletonList(createPatient(1));
@ -3082,7 +3094,7 @@ public class AuthorizationInterceptorR4Test {
status = ourClient.execute(httpDelete); status = ourClient.execute(httpDelete);
extractResponseAndClose(status); extractResponseAndClose(status);
assertEquals(403, status.getStatusLine().getStatusCode()); assertEquals(403, status.getStatusLine().getStatusCode());
assertTrue(ourHitMethod); assertFalse(ourHitMethod);
} }
@Test @Test

View File

@ -210,6 +210,11 @@
RuleBuilder, in order to ensure that cascading deletes are only available RuleBuilder, in order to ensure that cascading deletes are only available
to users with sufficient permission. to users with sufficient permission.
</action> </action>
<action type="add">
AuthorizationInterceptor will now try to block delete operations sooner
in the processing lifecycle if there is no chance they will be permitted
later (i.e. because the type is not authorized at all)
</action>
</release> </release>
<release version="3.8.0" date="2019-05-30" description="Hippo"> <release version="3.8.0" date="2019-05-30" description="Hippo">
<action type="fix"> <action type="fix">