Work on auth interceptor

This commit is contained in:
jamesagnew 2016-04-04 06:21:49 -04:00
parent a6b6f5467b
commit 891dddff1e
5 changed files with 192 additions and 106 deletions

View File

@ -117,23 +117,22 @@ public class AuthorizationInterceptor extends InterceptorAdapter implements ISer
return new Verdict(result, decidingRule);
}
private List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
ArrayList<IAuthRule> retVal = new ArrayList<IAuthRule>();
buildRuleList(theRequestDetails, new RuleBuilder(retVal));
return retVal;
}
/**
* Subclasses should override this method to supply the set of rules to be applied to
* this individual request.
* <p>
* Typically this is done by examining <code>theRequestDetails</code> to find
* out who the current user is and then using a {@link RuleBuilder} to create
* an appropriate rule chain.
* </p>
*
* @param theRequestDetails The individual request currently being applied
* @param theRuleBuilder The builder used to create the rules
*/
protected void buildRuleList(RequestDetails theRequestDetails, IAuthRuleBuilder theRuleBuilder) {
// nothing by default
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
return new ArrayList<IAuthRule>();
}
private OperationExamineDirection determineOperationDirection(RestOperationTypeEnum theOperation) {
switch (theOperation) {
case ADD_TAGS:

View File

@ -1,5 +1,7 @@
package ca.uhn.fhir.rest.server.interceptor.auth;
import java.util.List;
/*
* #%L
* HAPI FHIR - Core Library
@ -33,11 +35,6 @@ public interface IAuthRuleBuilder {
*/
IAuthRuleBuilderRule allow();
/**
* Start a new rule to deny a given operation
*/
IAuthRuleBuilderRule deny();
/**
* Start a new rule to allow a given operation
*
@ -48,16 +45,6 @@ public interface IAuthRuleBuilder {
*/
IAuthRuleBuilderRule allow(String theRuleName);
/**
* Start a new rule to deny a given operation
*
* @param theRuleName
* The name of this rule. The rule name is used for logging and error messages,
* and could be shown to the client, but has no semantic meaning within
* HAPI FHIR.
*/
IAuthRuleBuilderRule deny(String theRuleName);
/**
* This rule allows any invocation to proceed. It is intended to be
* used at the end of a chain that contains {@link #deny()} rules in
@ -82,6 +69,26 @@ public interface IAuthRuleBuilder {
*/
IAuthRuleBuilderRuleOpClassifierFinished allowAll(String theRuleName);
/**
* Build the rule list
*/
List<IAuthRule> build();
/**
* Start a new rule to deny a given operation
*/
IAuthRuleBuilderRule deny();
/**
* Start a new rule to deny a given operation
*
* @param theRuleName
* The name of this rule. The rule name is used for logging and error messages,
* and could be shown to the client, but has no semantic meaning within
* HAPI FHIR.
*/
IAuthRuleBuilderRule deny(String theRuleName);
/**
* This rule allows any invocation to proceed. It is intended to be
* used at the end of a chain that contains {@link #allow()} rules in

View File

@ -1,5 +1,7 @@
package ca.uhn.fhir.rest.server.interceptor.auth;
import java.util.List;
/*
* #%L
* HAPI FHIR - Core Library
@ -21,10 +23,14 @@ package ca.uhn.fhir.rest.server.interceptor.auth;
*/
public interface IAuthRuleBuilderRuleOpClassifierFinished {
/**
* Start another rule
*/
IAuthRuleBuilder andThen();
/**
* Build the rule list
*/
List<IAuthRule> build();
}

View File

@ -1,5 +1,7 @@
package ca.uhn.fhir.rest.server.interceptor.auth;
import java.util.ArrayList;
/*
* #%L
* HAPI FHIR - Core Library
@ -29,16 +31,12 @@ import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
class RuleBuilder implements IAuthRuleBuilder {
public class RuleBuilder implements IAuthRuleBuilder {
private RuleVerdictEnum myRuleMode;
private ArrayList<IAuthRule> myRules;
private String myRuleName;
private List<IAuthRule> myRules;
public RuleBuilder(List<IAuthRule> theRules) {
myRules = theRules;
public RuleBuilder() {
myRules = new ArrayList<IAuthRule>();
}
@Override
@ -48,9 +46,7 @@ class RuleBuilder implements IAuthRuleBuilder {
@Override
public IAuthRuleBuilderRule allow(String theRuleName) {
myRuleMode = RuleVerdictEnum.ALLOW;
myRuleName = theRuleName;
return new RuleBuilderRule();
return new RuleBuilderRule(RuleVerdictEnum.ALLOW, theRuleName);
}
@Override
@ -61,7 +57,12 @@ class RuleBuilder implements IAuthRuleBuilder {
@Override
public IAuthRuleBuilderRuleOpClassifierFinished allowAll(String theRuleName) {
myRules.add(new Rule(theRuleName).setOp(RuleOpEnum.ALLOW_ALL));
return new RuleBuilderFinished(myRules);
return new RuleBuilderFinished();
}
@Override
public List<IAuthRule> build() {
return myRules;
}
@Override
@ -71,9 +72,7 @@ class RuleBuilder implements IAuthRuleBuilder {
@Override
public IAuthRuleBuilderRule deny(String theRuleName) {
myRuleMode = RuleVerdictEnum.DENY;
myRuleName = theRuleName;
return new RuleBuilderRule();
return new RuleBuilderRule(RuleVerdictEnum.DENY, theRuleName);
}
@Override
@ -84,25 +83,32 @@ class RuleBuilder implements IAuthRuleBuilder {
@Override
public IAuthRuleBuilderRuleOpClassifierFinished denyAll(String theRuleName) {
myRules.add(new Rule(theRuleName).setOp(RuleOpEnum.DENY_ALL));
return new RuleBuilderFinished(myRules);
return new RuleBuilderFinished();
}
private static final class RuleBuilderFinished implements IAuthRuleBuilderRuleOpClassifierFinished {
private List<IAuthRule> myRules;
public RuleBuilderFinished(List<IAuthRule> theRules) {
myRules = theRules;
}
private final class RuleBuilderFinished implements IAuthRuleBuilderRuleOpClassifierFinished {
@Override
public IAuthRuleBuilder andThen() {
return new RuleBuilder(myRules);
return RuleBuilder.this;
}
@Override
public List<IAuthRule> build() {
return myRules;
}
}
class RuleBuilderRule implements IAuthRuleBuilderRule {
private class RuleBuilderRule implements IAuthRuleBuilderRule {
private RuleOpEnum myRuleOp;
private RuleVerdictEnum myRuleMode;
private String myRuleName;
public RuleBuilderRule(RuleVerdictEnum theRuleMode, String theRuleName) {
myRuleMode = theRuleMode;
myRuleName = theRuleName;
}
@Override
public RuleBuilderFinished metadata() {
@ -110,7 +116,7 @@ class RuleBuilder implements IAuthRuleBuilder {
rule.setOp(RuleOpEnum.METADATA);
rule.setMode(myRuleMode);
myRules.add(rule);
return new RuleBuilderFinished(myRules);
return new RuleBuilderFinished();
}
@Override
@ -131,7 +137,7 @@ class RuleBuilder implements IAuthRuleBuilder {
return new RuleBuilderRuleOp();
}
public class RuleBuilderRuleOp implements IAuthRuleBuilderRuleOp {
private class RuleBuilderRuleOp implements IAuthRuleBuilderRuleOp {
private AppliesTypeEnum myAppliesTo;
private Set<?> myAppliesToTypes;
@ -150,7 +156,7 @@ class RuleBuilder implements IAuthRuleBuilder {
return new RuleBuilderRuleOpClassifier();
}
public class RuleBuilderRuleOpClassifier implements IAuthRuleBuilderRuleOpClassifier {
private class RuleBuilderRuleOpClassifier implements IAuthRuleBuilderRuleOpClassifier {
private ClassifierTypeEnum myClassifierType;
private String myInCompartmentName;
@ -168,7 +174,7 @@ class RuleBuilder implements IAuthRuleBuilder {
rule.setClassifierCompartmentOwners(myInCompartmentOwners);
myRules.add(rule);
return new RuleBuilderFinished(myRules);
return new RuleBuilderFinished();
}
@Override
@ -209,23 +215,22 @@ class RuleBuilder implements IAuthRuleBuilder {
}
public class RuleBuilderRuleTransaction implements IAuthRuleBuilderRuleTransaction {
private class RuleBuilderRuleTransaction implements IAuthRuleBuilderRuleTransaction {
@Override
public IAuthRuleBuilderRuleTransactionOp withAnyOperation() {
return new RuleBuilderRuleTransactionOp();
}
class RuleBuilderRuleTransactionOp implements IAuthRuleBuilderRuleTransactionOp {
private class RuleBuilderRuleTransactionOp implements IAuthRuleBuilderRuleTransactionOp {
@Override
public IAuthRuleBuilderRuleOpClassifierFinished andApplyNormalRules() {
Rule rule = new Rule(myRuleName);
rule.setMode(myRuleMode);
rule.setOp(myRuleOp);
rule.setTransactionAppliesToOp(TransactionAppliesToEnum.ANY_OPERATION);
myRules.add(rule);
return new RuleBuilderFinished(myRules);
return new RuleBuilderFinished();
}
}

View File

@ -1,7 +1,10 @@
package ca.uhn.fhir.rest.server.interceptor.auth;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.util.ArrayList;
@ -34,8 +37,10 @@ import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu2.composite.ResourceReferenceDt;
import ca.uhn.fhir.model.dstu2.resource.Bundle;
import ca.uhn.fhir.model.dstu2.resource.Observation;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.dstu2.valueset.BundleTypeEnum;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.annotation.Create;
import ca.uhn.fhir.rest.annotation.Delete;
@ -43,6 +48,8 @@ import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.rest.annotation.ResourceParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.annotation.Transaction;
import ca.uhn.fhir.rest.annotation.TransactionParam;
import ca.uhn.fhir.rest.annotation.Update;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.method.IRequestOperationCallback;
@ -61,7 +68,7 @@ public class AuthorizationInterceptorDstu2Test {
private static boolean ourHitMethod;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(AuthorizationInterceptorDstu2Test.class);
private static int ourPort;
private static List<IBaseResource> ourReturn;
private static List<IResource> ourReturn;
private static Server ourServer;
private static RestfulServer ourServlet;
@ -80,7 +87,7 @@ public class AuthorizationInterceptorDstu2Test {
return new StringEntity(out, ContentType.create(Constants.CT_FHIR_JSON, "UTF-8"));
}
private IBaseResource createObservation(Integer theId, String theSubjectId) {
private IResource createObservation(Integer theId, String theSubjectId) {
Observation retVal = new Observation();
if (theId != null) {
retVal.setId(new IdDt("Observation", (long) theId));
@ -90,7 +97,7 @@ public class AuthorizationInterceptorDstu2Test {
return retVal;
}
private IBaseResource createPatient(Integer theId) {
private IResource createPatient(Integer theId) {
Patient retVal = new Patient();
if (theId != null) {
retVal.setId(new IdDt("Patient", (long) theId));
@ -113,8 +120,12 @@ public class AuthorizationInterceptorDstu2Test {
public void testMetadataAllow() throws Exception {
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
@Override
protected void buildRuleList(RequestDetails theRequestDetails, IAuthRuleBuilder theRuleBuilder) {
theRuleBuilder.allow("Rule 1").metadata();
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
//@formatter:off
return new RuleBuilder()
.allow("Rule 1").metadata()
.build();
//@formatter:on
}
});
@ -134,34 +145,48 @@ public class AuthorizationInterceptorDstu2Test {
public void testTransactionWriteGood() throws Exception {
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
@Override
protected void buildRuleList(RequestDetails theRequestDetails, IAuthRuleBuilder theRuleBuilder) {
theRuleBuilder
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
//@formatter:off
return new RuleBuilder()
.allow("Rule 1").transaction().withAnyOperation().andApplyNormalRules().andThen()
.allow("Rule 2").write().allResources().inCompartment("Patient", new IdDt("Patient/1")).andThen()
.allow("Rule 2").read().allResources().inCompartment("Patient", new IdDt("Patient/1")).andThen();
.allow("Rule 2").read().allResources().inCompartment("Patient", new IdDt("Patient/1")).andThen()
.build();
//@formatter:on
}
});
Bundle input = new Bundle();
input.setType(BundleTypeEnum.TRANSACTION);
input.addEntry().setResource(createPatient(1)).getRequest().setUrl("/Patient");
Bundle output = new Bundle();
output.setType(BundleTypeEnum.TRANSACTION_RESPONSE);
output.addEntry().getResponse().setLocation("/Patient/1");
// HttpGet httpGet;
// HttpResponse status;
// String response;
//
// ourReturn = Arrays.asList(createPatient(2));
// ourHitMethod = false;
// httpGet = new HttpGet("http://localhost:" + ourPort + "/metadata");
// status = ourClient.execute(httpGet);
// extractResponseAndClose(status);
// assertEquals(200, status.getStatusLine().getStatusCode());
HttpPost httpPost;
HttpResponse status;
String response;
ourReturn = Arrays.asList((IResource)output);
ourHitMethod = false;
httpPost = new HttpPost("http://localhost:" + ourPort + "/");
httpPost.setEntity(createFhirResourceEntity(input));
status = ourClient.execute(httpPost);
extractResponseAndClose(status);
assertEquals(200, status.getStatusLine().getStatusCode());
}
@Test
public void testMetadataDeny() throws Exception {
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.ALLOW) {
@Override
protected void buildRuleList(RequestDetails theRequestDetails, IAuthRuleBuilder theRuleBuilder) {
theRuleBuilder.deny("Rule 1").metadata();
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
//@formatter:off
return new RuleBuilder()
.deny("Rule 1").metadata()
.build();
//@formatter:on
}
});
@ -181,8 +206,12 @@ public class AuthorizationInterceptorDstu2Test {
public void testReadByAnyId() throws Exception {
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
@Override
protected void buildRuleList(RequestDetails theRequestDetails, IAuthRuleBuilder theRuleBuilder) {
theRuleBuilder.allow("Rule 1").read().resourcesOfType(Patient.class).withAnyId();
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
//@formatter:off
return new RuleBuilder()
.allow("Rule 1").read().resourcesOfType(Patient.class).withAnyId()
.build();
//@formatter:on
}
});
@ -234,9 +263,13 @@ public class AuthorizationInterceptorDstu2Test {
public void testAllowAll() throws Exception {
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
@Override
protected void buildRuleList(RequestDetails theRequestDetails, IAuthRuleBuilder theRuleBuilder) {
theRuleBuilder.deny("Rule 1").read().resourcesOfType(Patient.class).withAnyId();
theRuleBuilder.allowAll("Default Rule");
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
//@formatter:off
return new RuleBuilder()
.deny("Rule 1").read().resourcesOfType(Patient.class).withAnyId().andThen()
.allowAll("Default Rule")
.build();
//@formatter:on
}
});
@ -267,9 +300,13 @@ public class AuthorizationInterceptorDstu2Test {
public void testDenyAll() throws Exception {
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
@Override
protected void buildRuleList(RequestDetails theRequestDetails, IAuthRuleBuilder theRuleBuilder) {
theRuleBuilder.allow().read().resourcesOfType(Patient.class).withAnyId();
theRuleBuilder.denyAll("Default Rule");
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
//@formatter:off
return new RuleBuilder()
.allow().read().resourcesOfType(Patient.class).withAnyId().andThen()
.denyAll("Default Rule")
.build();
//@formatter:on
}
});
@ -301,9 +338,13 @@ public class AuthorizationInterceptorDstu2Test {
public void testReadByCompartmentRight() throws Exception {
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
@Override
protected void buildRuleList(RequestDetails theRequestDetails, IAuthRuleBuilder theRuleBuilder) {
theRuleBuilder.allow("Rule 1").read().resourcesOfType(Patient.class).inCompartment("Patient", new IdDt("Patient/1"));
theRuleBuilder.allow("Rule 2").read().resourcesOfType(Observation.class).inCompartment("Patient", new IdDt("Patient/1"));
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
//@formatter:off
return new RuleBuilder()
.allow("Rule 1").read().resourcesOfType(Patient.class).inCompartment("Patient", new IdDt("Patient/1")).andThen()
.allow("Rule 2").read().resourcesOfType(Observation.class).inCompartment("Patient", new IdDt("Patient/1"))
.build();
//@formatter:on
}
});
@ -340,9 +381,13 @@ public class AuthorizationInterceptorDstu2Test {
public void testReadByCompartmentWrong() throws Exception {
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
@Override
protected void buildRuleList(RequestDetails theRequestDetails, IAuthRuleBuilder theRuleBuilder) {
theRuleBuilder.allow("Rule 1").read().resourcesOfType(Patient.class).inCompartment("Patient", new IdDt("Patient/1"));
theRuleBuilder.allow("Rule 2").read().resourcesOfType(Observation.class).inCompartment("Patient", new IdDt("Patient/1"));
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
//@formatter:off
return new RuleBuilder()
.allow("Rule 1").read().resourcesOfType(Patient.class).inCompartment("Patient", new IdDt("Patient/1")).andThen()
.allow("Rule 2").read().resourcesOfType(Observation.class).inCompartment("Patient", new IdDt("Patient/1"))
.build();
//@formatter:on
}
});
@ -396,9 +441,13 @@ public class AuthorizationInterceptorDstu2Test {
public void testWriteByCompartmentCreate() throws Exception {
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
@Override
protected void buildRuleList(RequestDetails theRequestDetails, IAuthRuleBuilder theRuleBuilder) {
theRuleBuilder.allow("Rule 1").write().resourcesOfType(Patient.class).inCompartment("Patient", new IdDt("Patient/1"));
theRuleBuilder.allow("Rule 2").write().resourcesOfType(Observation.class).inCompartment("Patient", new IdDt("Patient/1"));
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
//@formatter:off
return new RuleBuilder()
.allow("Rule 1").write().resourcesOfType(Patient.class).inCompartment("Patient", new IdDt("Patient/1")).andThen()
.allow("Rule 2").write().resourcesOfType(Observation.class).inCompartment("Patient", new IdDt("Patient/1"))
.build();
//@formatter:on
}
});
@ -436,9 +485,13 @@ public class AuthorizationInterceptorDstu2Test {
public void testWriteByCompartmentDelete() throws Exception {
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
@Override
protected void buildRuleList(RequestDetails theRequestDetails, IAuthRuleBuilder theRuleBuilder) {
theRuleBuilder.allow("Rule 1").write().resourcesOfType(Patient.class).inCompartment("Patient", new IdDt("Patient/1"));
theRuleBuilder.allow("Rule 2").write().resourcesOfType(Observation.class).inCompartment("Patient", new IdDt("Patient/1"));
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
//@formatter:off
return new RuleBuilder()
.allow("Rule 1").write().resourcesOfType(Patient.class).inCompartment("Patient", new IdDt("Patient/1")).andThen()
.allow("Rule 2").write().resourcesOfType(Observation.class).inCompartment("Patient", new IdDt("Patient/1"))
.build();
//@formatter:on
}
});
@ -466,9 +519,13 @@ public class AuthorizationInterceptorDstu2Test {
public void testWriteByCompartmentUpdate() throws Exception {
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
@Override
protected void buildRuleList(RequestDetails theRequestDetails, IAuthRuleBuilder theRuleBuilder) {
theRuleBuilder.allow("Rule 1").write().resourcesOfType(Patient.class).inCompartment("Patient", new IdDt("Patient/1"));
theRuleBuilder.allow("Rule 2").write().resourcesOfType(Observation.class).inCompartment("Patient", new IdDt("Patient/1"));
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
//@formatter:off
return new RuleBuilder()
.allow("Rule 1").write().resourcesOfType(Patient.class).inCompartment("Patient", new IdDt("Patient/1")).andThen()
.allow("Rule 2").write().resourcesOfType(Observation.class).inCompartment("Patient", new IdDt("Patient/1"))
.build();
//@formatter:on
}
});
@ -523,11 +580,13 @@ public class AuthorizationInterceptorDstu2Test {
DummyPatientResourceProvider patProvider = new DummyPatientResourceProvider();
DummyObservationResourceProvider obsProv = new DummyObservationResourceProvider();
PlainProvider plainProvider = new PlainProvider();
ServletHandler proxyHandler = new ServletHandler();
ourServlet = new RestfulServer(ourCtx);
ourServlet.setFhirContext(ourCtx);
ourServlet.setResourceProviders(patProvider, obsProv);
ourServlet.setPlainProviders(plainProvider);
ServletHolder servletHolder = new ServletHolder(ourServlet);
proxyHandler.addServletWithMapping(servletHolder, "/*");
ourServer.setHandler(proxyHandler);
@ -571,7 +630,7 @@ public class AuthorizationInterceptorDstu2Test {
}
@Search()
public List<IBaseResource> search() {
public List<IResource> search() {
ourHitMethod = true;
return ourReturn;
}
@ -588,6 +647,16 @@ public class AuthorizationInterceptorDstu2Test {
}
public static class PlainProvider
{
@Transaction()
public Bundle search(@TransactionParam Bundle theInput) {
ourHitMethod = true;
return (Bundle) ourReturn.get(0);
}
}
public static class DummyPatientResourceProvider implements IResourceProvider {
@Create()
@ -622,7 +691,7 @@ public class AuthorizationInterceptorDstu2Test {
}
@Search()
public List<IBaseResource> search() {
public List<IResource> search() {
ourHitMethod = true;
return ourReturn;
}