Allow patch to proceed with AuthorizationInterceptor
This commit is contained in:
parent
73ddf0e0d9
commit
65cc41e376
|
@ -0,0 +1,30 @@
|
|||
package example;
|
||||
|
||||
import org.hl7.fhir.dstu3.model.IdType;
|
||||
import org.hl7.fhir.dstu3.model.OperationOutcome;
|
||||
|
||||
import ca.uhn.fhir.rest.annotation.*;
|
||||
import ca.uhn.fhir.rest.api.PatchTypeEnum;
|
||||
|
||||
|
||||
public class PatchExamples {
|
||||
|
||||
//START SNIPPET: patch
|
||||
@Patch
|
||||
public OperationOutcome patientPatch(@IdParam IdType theId, PatchTypeEnum thePatchType, @ResourceParam String theBody) {
|
||||
|
||||
if (thePatchType == PatchTypeEnum.JSON_PATCH) {
|
||||
// do something
|
||||
}
|
||||
if (thePatchType == PatchTypeEnum.XML_PATCH) {
|
||||
// do something
|
||||
}
|
||||
|
||||
OperationOutcome retVal = new OperationOutcome();
|
||||
retVal.getText().setDivAsString("<div>OK</div>");
|
||||
return retVal;
|
||||
}
|
||||
//END SNIPPET: patch
|
||||
|
||||
|
||||
}
|
|
@ -154,6 +154,7 @@ public class AuthorizationInterceptor extends ServerOperationInterceptorAdapter
|
|||
|
||||
case CREATE:
|
||||
case UPDATE:
|
||||
case PATCH:
|
||||
// if (theRequestResource != null) {
|
||||
// if (theRequestResource.getIdElement() != null) {
|
||||
// if (theRequestResource.getIdElement().hasIdPart() == false) {
|
||||
|
|
|
@ -37,9 +37,7 @@ import ca.uhn.fhir.model.dstu2.valueset.BundleTypeEnum;
|
|||
import ca.uhn.fhir.model.dstu2.valueset.HTTPVerbEnum;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.annotation.*;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||
import ca.uhn.fhir.rest.api.ValidationModeEnum;
|
||||
import ca.uhn.fhir.rest.api.*;
|
||||
import ca.uhn.fhir.rest.method.IRequestOperationCallback;
|
||||
import ca.uhn.fhir.rest.method.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.*;
|
||||
|
@ -790,8 +788,8 @@ public class AuthorizationInterceptorDstu2Test {
|
|||
@Override
|
||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||
return new RuleBuilder()
|
||||
.allow("RULE 1").operation().named("opName").onAnyInstance().andThen()
|
||||
.build();
|
||||
.allow("RULE 1").operation().named("opName").onAnyInstance().andThen()
|
||||
.build();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1215,8 +1213,8 @@ public class AuthorizationInterceptorDstu2Test {
|
|||
@Override
|
||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||
return new RuleBuilder()
|
||||
.allow("Rule 1").read().resourcesOfType(Patient.class).inCompartment("Patient", new IdDt("Patient/1"))
|
||||
.build();
|
||||
.allow("Rule 1").read().resourcesOfType(Patient.class).inCompartment("Patient", new IdDt("Patient/1"))
|
||||
.build();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1264,8 +1262,8 @@ public class AuthorizationInterceptorDstu2Test {
|
|||
@Override
|
||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||
return new RuleBuilder()
|
||||
.allow("Rule 1").read().resourcesOfType(Patient.class).inCompartment("Patient", new IdDt("Patient/1"))
|
||||
.build();
|
||||
.allow("Rule 1").read().resourcesOfType(Patient.class).inCompartment("Patient", new IdDt("Patient/1"))
|
||||
.build();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1780,7 +1778,7 @@ public class AuthorizationInterceptorDstu2Test {
|
|||
@Test
|
||||
public void testInvalidInstanceIds() throws Exception {
|
||||
try {
|
||||
new RuleBuilder().allow("Rule 1").write().instance((String)null);
|
||||
new RuleBuilder().allow("Rule 1").write().instance((String) null);
|
||||
fail();
|
||||
} catch (NullPointerException e) {
|
||||
assertEquals("theId must not be null or empty", e.getMessage());
|
||||
|
@ -1810,13 +1808,50 @@ public class AuthorizationInterceptorDstu2Test {
|
|||
assertEquals("theId.getValue() must not be null or empty", e.getMessage());
|
||||
}
|
||||
try {
|
||||
new RuleBuilder().allow("Rule 1").write().instance(new IdDt("Observation", (String)null));
|
||||
new RuleBuilder().allow("Rule 1").write().instance(new IdDt("Observation", (String) null));
|
||||
fail();
|
||||
} catch (NullPointerException e) {
|
||||
assertEquals("theId must contain an ID part", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWritePatchByInstance() throws Exception {
|
||||
ourConditionalCreateId = "1";
|
||||
|
||||
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
||||
@Override
|
||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||
//@formatter:off
|
||||
return new RuleBuilder()
|
||||
.allow("Rule 1").write().instance("Patient/900").andThen()
|
||||
.build();
|
||||
//@formatter:on
|
||||
}
|
||||
});
|
||||
|
||||
HttpEntityEnclosingRequestBase httpPost;
|
||||
HttpResponse status;
|
||||
String response;
|
||||
|
||||
String input = "[ { \"op\": \"replace\", \"path\": \"/gender\", \"value\": \"male\" } ]";
|
||||
|
||||
ourHitMethod = false;
|
||||
httpPost = new HttpPatch("http://localhost:" + ourPort + "/Patient/900");
|
||||
httpPost.setEntity(new StringEntity(input, ContentType.parse("application/json-patch+json")));
|
||||
status = ourClient.execute(httpPost);
|
||||
response = extractResponseAndClose(status);
|
||||
assertEquals(204, status.getStatusLine().getStatusCode());
|
||||
assertTrue(ourHitMethod);
|
||||
|
||||
ourHitMethod = false;
|
||||
httpPost = new HttpPatch("http://localhost:" + ourPort + "/Patient/999");
|
||||
httpPost.setEntity(new StringEntity(input, ContentType.parse("application/json-patch+json")));
|
||||
status = ourClient.execute(httpPost);
|
||||
response = extractResponseAndClose(status);
|
||||
assertEquals(403, status.getStatusLine().getStatusCode());
|
||||
assertFalse(ourHitMethod);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteByInstance() throws Exception {
|
||||
|
@ -1874,7 +1909,6 @@ public class AuthorizationInterceptorDstu2Test {
|
|||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testReadByInstance() throws Exception {
|
||||
ourConditionalCreateId = "1";
|
||||
|
@ -1922,7 +1956,6 @@ public class AuthorizationInterceptorDstu2Test {
|
|||
|
||||
}
|
||||
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() throws Exception {
|
||||
ourServer.stop();
|
||||
|
@ -2109,7 +2142,6 @@ public class AuthorizationInterceptorDstu2Test {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Class<? extends IResource> getResourceType() {
|
||||
return Patient.class;
|
||||
|
@ -2183,6 +2215,14 @@ public class AuthorizationInterceptorDstu2Test {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
@Patch()
|
||||
public MethodOutcome patch(@IdParam IdDt theId, @ResourceParam String theResource, PatchTypeEnum thePatchType) {
|
||||
ourHitMethod = true;
|
||||
|
||||
MethodOutcome retVal = new MethodOutcome();
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Validate
|
||||
public MethodOutcome validate(@ResourceParam Patient theResource, @IdParam IdDt theId, @ResourceParam String theRawResource, @ResourceParam EncodingEnum theEncoding,
|
||||
@Validate.Mode ValidationModeEnum theMode, @Validate.Profile String theProfile, RequestDetails theRequestDetails) {
|
||||
|
@ -2225,5 +2265,4 @@ public class AuthorizationInterceptorDstu2Test {
|
|||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -173,7 +173,6 @@ public class PatchDstu3Test {
|
|||
return Patient.class;
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
@Patch
|
||||
public OperationOutcome patientPatch(@IdParam IdType theId, PatchTypeEnum thePatchType, @ResourceParam String theBody) {
|
||||
ourLastMethod = "patientPatch";
|
||||
|
@ -184,7 +183,6 @@ public class PatchDstu3Test {
|
|||
retVal.getText().setDivAsString("<div>OK</div>");
|
||||
return retVal;
|
||||
}
|
||||
//@formatter:on
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -145,6 +145,10 @@
|
|||
to display the request headers and response headers, and individual lines
|
||||
may be highlighted.
|
||||
</action>
|
||||
<action type="fix">
|
||||
AuthorizationInterceptor did not permit PATCH operations to proceed even
|
||||
if the user had write access for the resource being patched.
|
||||
</action>
|
||||
</release>
|
||||
<release version="2.5" date="2017-06-08">
|
||||
<action type="fix">
|
||||
|
|
|
@ -1441,6 +1441,29 @@ If-Match: W/"3"]]></pre>
|
|||
<a name="exceptions" />
|
||||
</section>
|
||||
|
||||
|
||||
<section name="Instance Level - Patch">
|
||||
|
||||
<p>
|
||||
HAPI FHIR includes basic support for the
|
||||
<a href="http://hl7.org/implement/standards/fhir/http.html#patch">
|
||||
<b>patch</b>
|
||||
</a>
|
||||
operation. This support allows you to perform patches, but does not
|
||||
include logic to actually implement resource patching in the server
|
||||
framework (note that the JPA server does include a patch implementation).
|
||||
</p>
|
||||
<p>
|
||||
The following snippet shows how to define a patch method on a server:
|
||||
</p>
|
||||
|
||||
<macro name="snippet">
|
||||
<param name="id" value="patch" />
|
||||
<param name="file" value="examples/src/main/java/example/PatchExamples.java" />
|
||||
</macro>
|
||||
</patch>
|
||||
|
||||
|
||||
<!-- ****************************************************************** -->
|
||||
<!-- ****************************************************************** -->
|
||||
<!-- ****************************************************************** -->
|
||||
|
|
Loading…
Reference in New Issue