Get security interceptor working
This commit is contained in:
parent
533c0c87ab
commit
3f2b5fdeb7
|
@ -441,6 +441,16 @@ public interface IServerInterceptor {
|
||||||
myResource = theObject;
|
myResource = theObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method may be invoked by user code to notify interceptors that a nested
|
||||||
|
* operation is being invoked which is denoted by this request details.
|
||||||
|
*/
|
||||||
|
public void notifyIncomingRequestPreHandled(RestOperationTypeEnum theOperationType) {
|
||||||
|
for (IServerInterceptor next : getRequestDetails().getServer().getInterceptors()) {
|
||||||
|
next.incomingRequestPreHandled(theOperationType, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ import ca.uhn.fhir.model.api.TagList;
|
||||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||||
import ca.uhn.fhir.rest.method.RequestDetails;
|
import ca.uhn.fhir.rest.method.RequestDetails;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
|
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.ForbiddenOperationException;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.IServerOperationInterceptor;
|
import ca.uhn.fhir.rest.server.interceptor.IServerOperationInterceptor;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.InterceptorAdapter;
|
import ca.uhn.fhir.rest.server.interceptor.InterceptorAdapter;
|
||||||
import ca.uhn.fhir.util.BundleUtil;
|
import ca.uhn.fhir.util.BundleUtil;
|
||||||
|
@ -49,7 +50,7 @@ import ca.uhn.fhir.util.CoverageIgnore;
|
||||||
* inspect requests and responses to determine whether the calling user
|
* inspect requests and responses to determine whether the calling user
|
||||||
* has permission to perform the given action.
|
* has permission to perform the given action.
|
||||||
*/
|
*/
|
||||||
public class AuthorizationInterceptor extends InterceptorAdapter implements IServerOperationInterceptor {
|
public class AuthorizationInterceptor extends InterceptorAdapter implements IServerOperationInterceptor, IRuleApplier {
|
||||||
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(AuthorizationInterceptor.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(AuthorizationInterceptor.class);
|
||||||
|
|
||||||
|
@ -72,9 +73,8 @@ public class AuthorizationInterceptor extends InterceptorAdapter implements ISer
|
||||||
setDefaultPolicy(theDefaultPolicy);
|
setDefaultPolicy(theDefaultPolicy);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyRulesAndFailIfDeny(List<IAuthRule> theRules, RestOperationTypeEnum theOperation, RequestDetails theRequestDetails, IBaseResource theInputResource, IBaseResource theOutputResource) {
|
private void applyRulesAndFailIfDeny(RestOperationTypeEnum theOperation, RequestDetails theRequestDetails, IBaseResource theInputResource, IBaseResource theOutputResource) {
|
||||||
ourLog.trace("Applying {} rules to render an auth decision for operation {}", theRules.size(), theOperation);
|
Verdict decision = applyRulesAndReturnDecision(theOperation, theRequestDetails, theInputResource, theOutputResource);
|
||||||
Verdict decision = applyRulesAndReturnDecision(theRules, theOperation, theRequestDetails, theInputResource, theOutputResource);
|
|
||||||
|
|
||||||
if (decision.getDecision() == PolicyEnum.ALLOW) {
|
if (decision.getDecision() == PolicyEnum.ALLOW) {
|
||||||
return;
|
return;
|
||||||
|
@ -83,38 +83,26 @@ public class AuthorizationInterceptor extends InterceptorAdapter implements ISer
|
||||||
handleDeny(decision);
|
handleDeny(decision);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Verdict applyRulesAndReturnDecision(List<IAuthRule> theRules, RestOperationTypeEnum theOperation, RequestDetails theRequestDetails, IBaseResource theInputResource, IBaseResource theOutputResource) {
|
@Override
|
||||||
PolicyEnum result = null;
|
public Verdict applyRulesAndReturnDecision(RestOperationTypeEnum theOperation, RequestDetails theRequestDetails, IBaseResource theInputResource, IBaseResource theOutputResource) {
|
||||||
// PolicyEnum preference = null;
|
List<IAuthRule> rules = buildRuleList(theRequestDetails);
|
||||||
IAuthRule decidingRule = null;
|
ourLog.trace("Applying {} rules to render an auth decision for operation {}", rules.size(), theOperation);
|
||||||
|
|
||||||
for (IAuthRule nextRule : theRules) {
|
Verdict verdict = null;
|
||||||
RuleVerdictEnum decision = nextRule.applyRule(theOperation, theRequestDetails, theInputResource, theOutputResource);
|
for (IAuthRule nextRule : rules) {
|
||||||
|
verdict = nextRule.applyRule(theOperation, theRequestDetails, theInputResource, theOutputResource, this);
|
||||||
switch (decision) {
|
if (verdict != null) {
|
||||||
case NO_DECISION:
|
ourLog.trace("Rule {} returned decision {}", nextRule, verdict.getDecision());
|
||||||
continue;
|
|
||||||
case ALLOW:
|
|
||||||
result = PolicyEnum.ALLOW;
|
|
||||||
decidingRule = nextRule;
|
|
||||||
break;
|
|
||||||
case DENY:
|
|
||||||
result = PolicyEnum.DENY;
|
|
||||||
decidingRule = nextRule;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result != null) {
|
|
||||||
ourLog.trace("Rule {} returned decision {}", nextRule, result);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == null) {
|
if (verdict == null) {
|
||||||
ourLog.trace("No rules returned a decision, applying default {}", myDefaultPolicy);
|
ourLog.trace("No rules returned a decision, applying default {}", myDefaultPolicy);
|
||||||
result = myDefaultPolicy;
|
return new Verdict(myDefaultPolicy, null);
|
||||||
}
|
}
|
||||||
return new Verdict(result, decidingRule);
|
|
||||||
|
return verdict;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -197,22 +185,21 @@ public class AuthorizationInterceptor extends InterceptorAdapter implements ISer
|
||||||
* Handle an access control verdict of {@link PolicyEnum#DENY}.
|
* Handle an access control verdict of {@link PolicyEnum#DENY}.
|
||||||
* <p>
|
* <p>
|
||||||
* Subclasses may override to implement specific behaviour, but default is to
|
* Subclasses may override to implement specific behaviour, but default is to
|
||||||
* throw {@link AuthenticationException} (HTTP 401) with error message citing the
|
* throw {@link ForbiddenOperationException} (HTTP 403) with error message citing the
|
||||||
* rule name which trigered failure
|
* rule name which trigered failure
|
||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
protected void handleDeny(Verdict decision) {
|
protected void handleDeny(Verdict decision) {
|
||||||
if (decision.getDecidingRule() != null) {
|
if (decision.getDecidingRule() != null) {
|
||||||
String ruleName = defaultString(decision.getDecidingRule().getName(), "(unnamed rule)");
|
String ruleName = defaultString(decision.getDecidingRule().getName(), "(unnamed rule)");
|
||||||
throw new AuthenticationException("Access denied by rule: " + ruleName);
|
throw new ForbiddenOperationException("Access denied by rule: " + ruleName);
|
||||||
} else {
|
} else {
|
||||||
throw new AuthenticationException("Access denied by default policy (no applicable rules)");
|
throw new ForbiddenOperationException("Access denied by default policy (no applicable rules)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleUserOperation(RequestDetails theRequest, IBaseResource theResource, RestOperationTypeEnum operation) {
|
private void handleUserOperation(RequestDetails theRequest, IBaseResource theResource, RestOperationTypeEnum operation) {
|
||||||
List<IAuthRule> rules = buildRuleList(theRequest);
|
applyRulesAndFailIfDeny(operation, theRequest, theResource, null);
|
||||||
applyRulesAndFailIfDeny(rules, operation, theRequest, theResource, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -227,8 +214,7 @@ public class AuthorizationInterceptor extends InterceptorAdapter implements ISer
|
||||||
}
|
}
|
||||||
|
|
||||||
RequestDetails requestDetails = theProcessedRequest.getRequestDetails();
|
RequestDetails requestDetails = theProcessedRequest.getRequestDetails();
|
||||||
List<IAuthRule> rules = buildRuleList(requestDetails);
|
applyRulesAndFailIfDeny(theOperation, requestDetails, theProcessedRequest.getResource(), null);
|
||||||
applyRulesAndFailIfDeny(rules, theOperation, requestDetails, theProcessedRequest.getResource(), null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -281,7 +267,7 @@ public class AuthorizationInterceptor extends InterceptorAdapter implements ISer
|
||||||
}
|
}
|
||||||
|
|
||||||
for (IBaseResource nextResponse : resources) {
|
for (IBaseResource nextResponse : resources) {
|
||||||
applyRulesAndFailIfDeny(rules, theRequestDetails.getRestOperationType(), theRequestDetails, null, nextResponse);
|
applyRulesAndFailIfDeny(theRequestDetails.getRestOperationType(), theRequestDetails, null, nextResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -24,6 +24,7 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
|
||||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||||
import ca.uhn.fhir.rest.method.RequestDetails;
|
import ca.uhn.fhir.rest.method.RequestDetails;
|
||||||
|
import ca.uhn.fhir.rest.server.interceptor.auth.AuthorizationInterceptor.Verdict;
|
||||||
|
|
||||||
public interface IAuthRule {
|
public interface IAuthRule {
|
||||||
|
|
||||||
|
@ -38,9 +39,12 @@ public interface IAuthRule {
|
||||||
* The resource being input by the client, or <code>null</code>
|
* The resource being input by the client, or <code>null</code>
|
||||||
* @param theOutputResource
|
* @param theOutputResource
|
||||||
* The resource being returned by the server, or <code>null</code>
|
* The resource being returned by the server, or <code>null</code>
|
||||||
* @return Returns a policy decision, or {@link RuleVerdictEnum#NO_DECISION} if the rule does not apply
|
* @param theRuleApplier
|
||||||
|
* The rule applying module (this can be used by rules to apply the rule set to
|
||||||
|
* nested objects in the request, such as nested requests in a transaction)
|
||||||
|
* @return Returns a policy decision, or <code>null</code> if the rule does not apply
|
||||||
*/
|
*/
|
||||||
RuleVerdictEnum applyRule(RestOperationTypeEnum theOperation, RequestDetails theRequestDetails, IBaseResource theInputResource, IBaseResource theOutputResource);
|
Verdict applyRule(RestOperationTypeEnum theOperation, RequestDetails theRequestDetails, IBaseResource theInputResource, IBaseResource theOutputResource, IRuleApplier theRuleApplier);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a name for this rule, to be used in logs and error messages
|
* Returns a name for this rule, to be used in logs and error messages
|
||||||
|
|
|
@ -22,6 +22,11 @@ package ca.uhn.fhir.rest.server.interceptor.auth;
|
||||||
|
|
||||||
public interface IAuthRuleBuilderRule {
|
public interface IAuthRuleBuilderRule {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This rule applies to the FHIR delete operation
|
||||||
|
*/
|
||||||
|
IAuthRuleBuilderRuleOp delete();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This rules applies to the metadata operation (retrieve the
|
* This rules applies to the metadata operation (retrieve the
|
||||||
* server's conformance statement)
|
* server's conformance statement)
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
package ca.uhn.fhir.rest.server.interceptor.auth;
|
||||||
|
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||||
|
import ca.uhn.fhir.rest.method.RequestDetails;
|
||||||
|
import ca.uhn.fhir.rest.server.interceptor.auth.AuthorizationInterceptor.Verdict;
|
||||||
|
|
||||||
|
public interface IRuleApplier {
|
||||||
|
|
||||||
|
Verdict applyRulesAndReturnDecision(RestOperationTypeEnum theOperation, RequestDetails theRequestDetails, IBaseResource theInputResource, IBaseResource theOutputResource);
|
||||||
|
|
||||||
|
}
|
|
@ -21,16 +21,23 @@ package ca.uhn.fhir.rest.server.interceptor.auth;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseBundle;
|
import org.hl7.fhir.instance.model.api.IBaseBundle;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
|
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||||
import ca.uhn.fhir.rest.method.RequestDetails;
|
import ca.uhn.fhir.rest.method.RequestDetails;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
|
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.FhirTerser;
|
import ca.uhn.fhir.util.FhirTerser;
|
||||||
|
|
||||||
class Rule implements IAuthRule {
|
class Rule implements IAuthRule {
|
||||||
|
@ -40,7 +47,7 @@ class Rule implements IAuthRule {
|
||||||
private String myClassifierCompartmentName;
|
private String myClassifierCompartmentName;
|
||||||
private Collection<? extends IIdType> myClassifierCompartmentOwners;
|
private Collection<? extends IIdType> myClassifierCompartmentOwners;
|
||||||
private ClassifierTypeEnum myClassifierType;
|
private ClassifierTypeEnum myClassifierType;
|
||||||
private RuleVerdictEnum myMode;
|
private PolicyEnum myMode;
|
||||||
private String myName;
|
private String myName;
|
||||||
private RuleOpEnum myOp;
|
private RuleOpEnum myOp;
|
||||||
private TransactionAppliesToEnum myTransactionAppliesToOp;
|
private TransactionAppliesToEnum myTransactionAppliesToOp;
|
||||||
|
@ -50,33 +57,107 @@ class Rule implements IAuthRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RuleVerdictEnum applyRule(RestOperationTypeEnum theOperation, RequestDetails theRequestDetails, IBaseResource theInputResource, IBaseResource theOutputResource) {
|
public Verdict applyRule(RestOperationTypeEnum theOperation, RequestDetails theRequestDetails, IBaseResource theInputResource, IBaseResource theOutputResource, IRuleApplier theRuleApplier) {
|
||||||
FhirContext ctx = theRequestDetails.getServer().getFhirContext();
|
FhirContext ctx = theRequestDetails.getServer().getFhirContext();
|
||||||
|
|
||||||
IBaseResource appliesTo;
|
IBaseResource appliesTo;
|
||||||
switch (myOp) {
|
switch (myOp) {
|
||||||
case READ:
|
case READ:
|
||||||
|
if (theOutputResource == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
appliesTo = theOutputResource;
|
appliesTo = theOutputResource;
|
||||||
break;
|
break;
|
||||||
case WRITE:
|
case WRITE:
|
||||||
|
if (theInputResource == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
appliesTo = theInputResource;
|
appliesTo = theInputResource;
|
||||||
break;
|
break;
|
||||||
|
case DELETE:
|
||||||
|
if (theOperation == RestOperationTypeEnum.DELETE) {
|
||||||
|
if (theInputResource == null) {
|
||||||
|
return new Verdict(myMode, this);
|
||||||
|
} else {
|
||||||
|
appliesTo = theInputResource;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case BATCH:
|
case BATCH:
|
||||||
case TRANSACTION:
|
case TRANSACTION:
|
||||||
if (requestAppliesToTransaction(ctx, myOp, theInputResource)) {
|
if (theInputResource != null && requestAppliesToTransaction(ctx, myOp, theInputResource)) {
|
||||||
return myMode;
|
if (myMode == PolicyEnum.DENY) {
|
||||||
|
return new Verdict(PolicyEnum.DENY, this);
|
||||||
|
} else {
|
||||||
|
List<BundleEntryParts> inputResources = BundleUtil.toListOfEntries(ctx, (IBaseBundle) theInputResource);
|
||||||
|
Verdict verdict = null;
|
||||||
|
for (BundleEntryParts nextPart : inputResources) {
|
||||||
|
|
||||||
|
IBaseResource inputResource = nextPart.getResource();
|
||||||
|
RestOperationTypeEnum operation = null;
|
||||||
|
if (nextPart.getRequestType() == RequestTypeEnum.GET) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (nextPart.getRequestType() == RequestTypeEnum.POST) {
|
||||||
|
operation = RestOperationTypeEnum.CREATE;
|
||||||
|
} else if (nextPart.getRequestType() == RequestTypeEnum.PUT) {
|
||||||
|
operation = RestOperationTypeEnum.UPDATE;
|
||||||
|
} else {
|
||||||
|
throw new InvalidRequestException("Can not handle transaction with operation of type " + nextPart.getRequestType());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is basically just being conservative - Be careful of transactions containing
|
||||||
|
* nested operations and nested transactions. We block the by default. At some point
|
||||||
|
* it would be nice to be more nuanced here.
|
||||||
|
*/
|
||||||
|
RuntimeResourceDefinition resourceDef = ctx.getResourceDefinition(nextPart.getResource());
|
||||||
|
if ("Parameters".equals(resourceDef.getName()) || "Bundle".equals(resourceDef.getName())) {
|
||||||
|
throw new InvalidRequestException("Can not handle transaction with nested resource of type " + resourceDef.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
Verdict newVerdict = theRuleApplier.applyRulesAndReturnDecision(operation, theRequestDetails, inputResource, null);
|
||||||
|
if (newVerdict == null) {
|
||||||
|
continue;
|
||||||
|
} else if (verdict == null) {
|
||||||
|
verdict = newVerdict;
|
||||||
|
} else if (verdict.getDecision() == PolicyEnum.ALLOW && newVerdict.getDecision() == PolicyEnum.DENY) {
|
||||||
|
verdict = newVerdict;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return verdict;
|
||||||
|
}
|
||||||
|
} else if (theOutputResource != null) {
|
||||||
|
List<BundleEntryParts> inputResources = BundleUtil.toListOfEntries(ctx, (IBaseBundle) theInputResource);
|
||||||
|
Verdict verdict = null;
|
||||||
|
for (BundleEntryParts nextPart : inputResources) {
|
||||||
|
if (nextPart.getResource() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Verdict newVerdict = theRuleApplier.applyRulesAndReturnDecision(RestOperationTypeEnum.READ, theRequestDetails, null, nextPart.getResource());
|
||||||
|
if (newVerdict == null) {
|
||||||
|
continue;
|
||||||
|
} else if (verdict == null) {
|
||||||
|
verdict = newVerdict;
|
||||||
|
} else if (verdict.getDecision() == PolicyEnum.ALLOW && newVerdict.getDecision() == PolicyEnum.DENY) {
|
||||||
|
verdict = newVerdict;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return verdict;
|
||||||
} else {
|
} else {
|
||||||
return RuleVerdictEnum.NO_DECISION;
|
return null;
|
||||||
}
|
}
|
||||||
case ALLOW_ALL:
|
case ALLOW_ALL:
|
||||||
return RuleVerdictEnum.ALLOW;
|
return new Verdict(PolicyEnum.ALLOW, this);
|
||||||
case DENY_ALL:
|
case DENY_ALL:
|
||||||
return RuleVerdictEnum.DENY;
|
return new Verdict(PolicyEnum.DENY, this);
|
||||||
case METADATA:
|
case METADATA:
|
||||||
if (theOperation == RestOperationTypeEnum.METADATA) {
|
if (theOperation == RestOperationTypeEnum.METADATA) {
|
||||||
return myMode;
|
return new Verdict(myMode, this);
|
||||||
} else {
|
} else {
|
||||||
return RuleVerdictEnum.NO_DECISION;
|
return null;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
// Should not happen
|
// Should not happen
|
||||||
|
@ -88,7 +169,7 @@ class Rule implements IAuthRule {
|
||||||
break;
|
break;
|
||||||
case TYPES:
|
case TYPES:
|
||||||
if (myAppliesToTypes.contains(appliesTo.getClass()) == false) {
|
if (myAppliesToTypes.contains(appliesTo.getClass()) == false) {
|
||||||
return RuleVerdictEnum.NO_DECISION;
|
return null;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -108,17 +189,21 @@ class Rule implements IAuthRule {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!foundMatch) {
|
if (!foundMatch) {
|
||||||
return RuleVerdictEnum.NO_DECISION;
|
return null;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalStateException("Unable to apply security to event of applies to type " + myAppliesTo);
|
throw new IllegalStateException("Unable to apply security to event of applies to type " + myAppliesTo);
|
||||||
}
|
}
|
||||||
|
|
||||||
return myMode;
|
return new Verdict(myMode, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean requestAppliesToTransaction(FhirContext theContext, RuleOpEnum theOp, IBaseResource theInputResource) {
|
private boolean requestAppliesToTransaction(FhirContext theContext, RuleOpEnum theOp, IBaseResource theInputResource) {
|
||||||
|
if (!"Bundle".equals(theContext.getResourceDefinition(theInputResource).getName())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
IBaseBundle request = (IBaseBundle) theInputResource;
|
IBaseBundle request = (IBaseBundle) theInputResource;
|
||||||
String bundleType = BundleUtil.getBundleType(theContext, request);
|
String bundleType = BundleUtil.getBundleType(theContext, request);
|
||||||
switch (theOp) {
|
switch (theOp) {
|
||||||
|
@ -160,7 +245,7 @@ class Rule implements IAuthRule {
|
||||||
myClassifierType = theClassifierType;
|
myClassifierType = theClassifierType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMode(RuleVerdictEnum theRuleMode) {
|
public void setMode(PolicyEnum theRuleMode) {
|
||||||
myMode = theRuleMode;
|
myMode = theRuleMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ public class RuleBuilder implements IAuthRuleBuilder {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IAuthRuleBuilderRule allow(String theRuleName) {
|
public IAuthRuleBuilderRule allow(String theRuleName) {
|
||||||
return new RuleBuilderRule(RuleVerdictEnum.ALLOW, theRuleName);
|
return new RuleBuilderRule(PolicyEnum.ALLOW, theRuleName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -72,7 +72,7 @@ public class RuleBuilder implements IAuthRuleBuilder {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IAuthRuleBuilderRule deny(String theRuleName) {
|
public IAuthRuleBuilderRule deny(String theRuleName) {
|
||||||
return new RuleBuilderRule(RuleVerdictEnum.DENY, theRuleName);
|
return new RuleBuilderRule(PolicyEnum.DENY, theRuleName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -101,15 +101,21 @@ public class RuleBuilder implements IAuthRuleBuilder {
|
||||||
|
|
||||||
private class RuleBuilderRule implements IAuthRuleBuilderRule {
|
private class RuleBuilderRule implements IAuthRuleBuilderRule {
|
||||||
|
|
||||||
private RuleOpEnum myRuleOp;
|
private PolicyEnum myRuleMode;
|
||||||
private RuleVerdictEnum myRuleMode;
|
|
||||||
private String myRuleName;
|
private String myRuleName;
|
||||||
|
private RuleOpEnum myRuleOp;
|
||||||
|
|
||||||
public RuleBuilderRule(RuleVerdictEnum theRuleMode, String theRuleName) {
|
public RuleBuilderRule(PolicyEnum theRuleMode, String theRuleName) {
|
||||||
myRuleMode = theRuleMode;
|
myRuleMode = theRuleMode;
|
||||||
myRuleName = theRuleName;
|
myRuleName = theRuleName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IAuthRuleBuilderRuleOp delete() {
|
||||||
|
myRuleOp = RuleOpEnum.DELETE;
|
||||||
|
return new RuleBuilderRuleOp();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RuleBuilderFinished metadata() {
|
public RuleBuilderFinished metadata() {
|
||||||
Rule rule = new Rule(myRuleName);
|
Rule rule = new Rule(myRuleName);
|
||||||
|
@ -118,13 +124,13 @@ public class RuleBuilder implements IAuthRuleBuilder {
|
||||||
myRules.add(rule);
|
myRules.add(rule);
|
||||||
return new RuleBuilderFinished();
|
return new RuleBuilderFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IAuthRuleBuilderRuleOp read() {
|
public IAuthRuleBuilderRuleOp read() {
|
||||||
myRuleOp = RuleOpEnum.READ;
|
myRuleOp = RuleOpEnum.READ;
|
||||||
return new RuleBuilderRuleOp();
|
return new RuleBuilderRuleOp();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IAuthRuleBuilderRuleTransaction transaction() {
|
public IAuthRuleBuilderRuleTransaction transaction() {
|
||||||
myRuleOp = RuleOpEnum.TRANSACTION;
|
myRuleOp = RuleOpEnum.TRANSACTION;
|
||||||
|
@ -136,7 +142,7 @@ public class RuleBuilder implements IAuthRuleBuilder {
|
||||||
myRuleOp = RuleOpEnum.WRITE;
|
myRuleOp = RuleOpEnum.WRITE;
|
||||||
return new RuleBuilderRuleOp();
|
return new RuleBuilderRuleOp();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class RuleBuilderRuleOp implements IAuthRuleBuilderRuleOp {
|
private class RuleBuilderRuleOp implements IAuthRuleBuilderRuleOp {
|
||||||
|
|
||||||
private AppliesTypeEnum myAppliesTo;
|
private AppliesTypeEnum myAppliesTo;
|
||||||
|
|
|
@ -27,5 +27,6 @@ enum RuleOpEnum {
|
||||||
DENY_ALL,
|
DENY_ALL,
|
||||||
TRANSACTION,
|
TRANSACTION,
|
||||||
METADATA,
|
METADATA,
|
||||||
BATCH
|
BATCH,
|
||||||
|
DELETE
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
package ca.uhn.fhir.rest.server.interceptor.auth;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* #%L
|
|
||||||
* HAPI FHIR - Core Library
|
|
||||||
* %%
|
|
||||||
* Copyright (C) 2014 - 2016 University Health Network
|
|
||||||
* %%
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
* #L%
|
|
||||||
*/
|
|
||||||
|
|
||||||
enum RuleVerdictEnum {
|
|
||||||
ALLOW,
|
|
||||||
DENY,
|
|
||||||
NO_DECISION
|
|
||||||
}
|
|
|
@ -1,5 +1,7 @@
|
||||||
package ca.uhn.fhir.util;
|
package ca.uhn.fhir.util;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* #%L
|
* #%L
|
||||||
* HAPI FHIR - Core Library
|
* HAPI FHIR - Core Library
|
||||||
|
@ -33,33 +35,13 @@ import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
|
||||||
import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
|
import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
|
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch resources from a bundle
|
* Fetch resources from a bundle
|
||||||
*/
|
*/
|
||||||
public class BundleUtil {
|
public class BundleUtil {
|
||||||
|
|
||||||
/**
|
|
||||||
* Extract all of the resources from a given bundle
|
|
||||||
*/
|
|
||||||
public static List<IBaseResource> toListOfResources(FhirContext theContext, IBaseBundle theBundle) {
|
|
||||||
List<IBaseResource> retVal = new ArrayList<IBaseResource>();
|
|
||||||
|
|
||||||
RuntimeResourceDefinition def = theContext.getResourceDefinition(theBundle);
|
|
||||||
BaseRuntimeChildDefinition entryChild = def.getChildByName("entry");
|
|
||||||
List<IBase> entries = entryChild.getAccessor().getValues(theBundle);
|
|
||||||
|
|
||||||
BaseRuntimeElementCompositeDefinition<?> entryChildElem = (BaseRuntimeElementCompositeDefinition<?>) entryChild.getChildByName("entry");
|
|
||||||
BaseRuntimeChildDefinition resourceChild = entryChildElem.getChildByName("resource");
|
|
||||||
for (IBase nextEntry : entries) {
|
|
||||||
for (IBase next : resourceChild.getAccessor().getValues(nextEntry)) {
|
|
||||||
retVal.add((IBaseResource) next);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static List<Pair<String, IBaseResource>> getBundleEntryUrlsAndResources(FhirContext theContext, IBaseBundle theBundle) {
|
public static List<Pair<String, IBaseResource>> getBundleEntryUrlsAndResources(FhirContext theContext, IBaseBundle theBundle) {
|
||||||
RuntimeResourceDefinition def = theContext.getResourceDefinition(theBundle);
|
RuntimeResourceDefinition def = theContext.getResourceDefinition(theBundle);
|
||||||
|
@ -96,7 +78,7 @@ public class BundleUtil {
|
||||||
|
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getBundleType(FhirContext theContext, IBaseBundle theBundle) {
|
public static String getBundleType(FhirContext theContext, IBaseBundle theBundle) {
|
||||||
RuntimeResourceDefinition def = theContext.getResourceDefinition(theBundle);
|
RuntimeResourceDefinition def = theContext.getResourceDefinition(theBundle);
|
||||||
BaseRuntimeChildDefinition entryChild = def.getChildByName("type");
|
BaseRuntimeChildDefinition entryChild = def.getChildByName("type");
|
||||||
|
@ -108,4 +90,96 @@ public class BundleUtil {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract all of the resources from a given bundle
|
||||||
|
*/
|
||||||
|
public static List<BundleEntryParts> toListOfEntries(FhirContext theContext, IBaseBundle theBundle) {
|
||||||
|
List<BundleEntryParts> retVal = new ArrayList<BundleEntryParts>();
|
||||||
|
|
||||||
|
RuntimeResourceDefinition def = theContext.getResourceDefinition(theBundle);
|
||||||
|
BaseRuntimeChildDefinition entryChild = def.getChildByName("entry");
|
||||||
|
List<IBase> entries = entryChild.getAccessor().getValues(theBundle);
|
||||||
|
|
||||||
|
BaseRuntimeElementCompositeDefinition<?> entryChildElem = (BaseRuntimeElementCompositeDefinition<?>) entryChild.getChildByName("entry");
|
||||||
|
|
||||||
|
BaseRuntimeChildDefinition resourceChild = entryChildElem.getChildByName("resource");
|
||||||
|
BaseRuntimeChildDefinition requestChild = entryChildElem.getChildByName("request");
|
||||||
|
BaseRuntimeElementCompositeDefinition<?> requestElem = (BaseRuntimeElementCompositeDefinition<?>) requestChild.getChildByName("request");
|
||||||
|
BaseRuntimeChildDefinition urlChild = requestElem.getChildByName("url");
|
||||||
|
BaseRuntimeChildDefinition methodChild = requestElem.getChildByName("method");
|
||||||
|
|
||||||
|
IBaseResource resource = null;
|
||||||
|
String url = null;
|
||||||
|
RequestTypeEnum requestType = null;
|
||||||
|
|
||||||
|
for (IBase nextEntry : entries) {
|
||||||
|
for (IBase next : resourceChild.getAccessor().getValues(nextEntry)) {
|
||||||
|
resource = (IBaseResource) next;
|
||||||
|
}
|
||||||
|
for (IBase nextRequest : requestChild.getAccessor().getValues(nextEntry)) {
|
||||||
|
for (IBase nextUrl : urlChild.getAccessor().getValues(nextRequest)) {
|
||||||
|
url = ((IPrimitiveType<?>)nextUrl).getValueAsString();
|
||||||
|
}
|
||||||
|
for (IBase nextUrl : methodChild.getAccessor().getValues(nextRequest)) {
|
||||||
|
String methodString = ((IPrimitiveType<?>)nextUrl).getValueAsString();
|
||||||
|
if (isNotBlank(methodString)) {
|
||||||
|
requestType = RequestTypeEnum.valueOf(methodString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* All 3 might be null - That's ok because we still want to know the
|
||||||
|
* order in the original bundle.
|
||||||
|
*/
|
||||||
|
retVal.add(new BundleEntryParts(requestType, url, resource));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract all of the resources from a given bundle
|
||||||
|
*/
|
||||||
|
public static List<IBaseResource> toListOfResources(FhirContext theContext, IBaseBundle theBundle) {
|
||||||
|
List<IBaseResource> retVal = new ArrayList<IBaseResource>();
|
||||||
|
|
||||||
|
RuntimeResourceDefinition def = theContext.getResourceDefinition(theBundle);
|
||||||
|
BaseRuntimeChildDefinition entryChild = def.getChildByName("entry");
|
||||||
|
List<IBase> entries = entryChild.getAccessor().getValues(theBundle);
|
||||||
|
|
||||||
|
BaseRuntimeElementCompositeDefinition<?> entryChildElem = (BaseRuntimeElementCompositeDefinition<?>) entryChild.getChildByName("entry");
|
||||||
|
BaseRuntimeChildDefinition resourceChild = entryChildElem.getChildByName("resource");
|
||||||
|
for (IBase nextEntry : entries) {
|
||||||
|
for (IBase next : resourceChild.getAccessor().getValues(nextEntry)) {
|
||||||
|
retVal.add((IBaseResource) next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class BundleEntryParts
|
||||||
|
{
|
||||||
|
private final RequestTypeEnum myRequestType;
|
||||||
|
private final IBaseResource myResource;
|
||||||
|
private final String myUrl;
|
||||||
|
public BundleEntryParts(RequestTypeEnum theRequestType, String theUrl, IBaseResource theResource) {
|
||||||
|
super();
|
||||||
|
myRequestType = theRequestType;
|
||||||
|
myUrl = theUrl;
|
||||||
|
myResource = theResource;
|
||||||
|
}
|
||||||
|
public RequestTypeEnum getRequestType() {
|
||||||
|
return myRequestType;
|
||||||
|
}
|
||||||
|
public IBaseResource getResource() {
|
||||||
|
return myResource;
|
||||||
|
}
|
||||||
|
public String getUrl() {
|
||||||
|
return myUrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -665,18 +665,21 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
theProvider.setSearchResultDao(mySearchResultDao);
|
theProvider.setSearchResultDao(mySearchResultDao);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void notifyInterceptors(RestOperationTypeEnum operationType, ActionRequestDetails requestDetails) {
|
protected void notifyInterceptors(RestOperationTypeEnum theOperationType, ActionRequestDetails requestDetails) {
|
||||||
if (requestDetails.getId() != null && requestDetails.getId().hasResourceType() && isNotBlank(requestDetails.getResourceType())) {
|
if (requestDetails.getId() != null && requestDetails.getId().hasResourceType() && isNotBlank(requestDetails.getResourceType())) {
|
||||||
if (requestDetails.getId().getResourceType().equals(requestDetails.getResourceType()) == false) {
|
if (requestDetails.getId().getResourceType().equals(requestDetails.getResourceType()) == false) {
|
||||||
throw new InternalErrorException("Inconsistent server state - Resource types don't match: " + requestDetails.getId().getResourceType() + " / " + requestDetails.getResourceType());
|
throw new InternalErrorException("Inconsistent server state - Resource types don't match: " + requestDetails.getId().getResourceType() + " / " + requestDetails.getResourceType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
requestDetails.notifyIncomingRequestPreHandled(theOperationType);
|
||||||
|
|
||||||
List<IServerInterceptor> interceptors = getConfig().getInterceptors();
|
List<IServerInterceptor> interceptors = getConfig().getInterceptors();
|
||||||
if (interceptors == null) {
|
if (interceptors == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (IServerInterceptor next : interceptors) {
|
for (IServerInterceptor next : interceptors) {
|
||||||
next.incomingRequestPreHandled(operationType, requestDetails);
|
next.incomingRequestPreHandled(theOperationType, requestDetails);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,267 @@
|
||||||
|
package ca.uhn.fhir.jpa.provider.dstu3;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.contains;
|
||||||
|
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||||
|
import static org.hamcrest.Matchers.containsInRelativeOrder;
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.hamcrest.Matchers.empty;
|
||||||
|
import static org.hamcrest.Matchers.greaterThan;
|
||||||
|
import static org.hamcrest.Matchers.hasItems;
|
||||||
|
import static org.hamcrest.Matchers.not;
|
||||||
|
import static org.hamcrest.Matchers.startsWith;
|
||||||
|
import static org.hamcrest.Matchers.stringContainsInOrder;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.SocketTimeoutException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.http.client.ClientProtocolException;
|
||||||
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
|
import org.apache.http.client.methods.HttpDelete;
|
||||||
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
import org.apache.http.client.methods.HttpPost;
|
||||||
|
import org.apache.http.client.methods.HttpPut;
|
||||||
|
import org.apache.http.entity.ContentType;
|
||||||
|
import org.apache.http.entity.StringEntity;
|
||||||
|
import org.hl7.fhir.dstu3.model.BaseResource;
|
||||||
|
import org.hl7.fhir.dstu3.model.Bundle;
|
||||||
|
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
|
||||||
|
import org.hl7.fhir.dstu3.model.Bundle.BundleType;
|
||||||
|
import org.hl7.fhir.dstu3.model.Bundle.HTTPVerb;
|
||||||
|
import org.hl7.fhir.dstu3.model.Bundle.SearchEntryMode;
|
||||||
|
import org.hl7.fhir.dstu3.model.CodeSystem;
|
||||||
|
import org.hl7.fhir.dstu3.model.Coding;
|
||||||
|
import org.hl7.fhir.dstu3.model.Condition;
|
||||||
|
import org.hl7.fhir.dstu3.model.DateTimeType;
|
||||||
|
import org.hl7.fhir.dstu3.model.DateType;
|
||||||
|
import org.hl7.fhir.dstu3.model.Device;
|
||||||
|
import org.hl7.fhir.dstu3.model.DiagnosticOrder;
|
||||||
|
import org.hl7.fhir.dstu3.model.DocumentManifest;
|
||||||
|
import org.hl7.fhir.dstu3.model.DocumentReference;
|
||||||
|
import org.hl7.fhir.dstu3.model.Encounter;
|
||||||
|
import org.hl7.fhir.dstu3.model.Encounter.EncounterClass;
|
||||||
|
import org.hl7.fhir.dstu3.model.Encounter.EncounterLocationComponent;
|
||||||
|
import org.hl7.fhir.dstu3.model.Encounter.EncounterState;
|
||||||
|
import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender;
|
||||||
|
import org.hl7.fhir.dstu3.model.IdType;
|
||||||
|
import org.hl7.fhir.dstu3.model.ImagingStudy;
|
||||||
|
import org.hl7.fhir.dstu3.model.InstantType;
|
||||||
|
import org.hl7.fhir.dstu3.model.Location;
|
||||||
|
import org.hl7.fhir.dstu3.model.Medication;
|
||||||
|
import org.hl7.fhir.dstu3.model.MedicationOrder;
|
||||||
|
import org.hl7.fhir.dstu3.model.Meta;
|
||||||
|
import org.hl7.fhir.dstu3.model.Narrative.NarrativeStatus;
|
||||||
|
import org.hl7.fhir.dstu3.model.Observation;
|
||||||
|
import org.hl7.fhir.dstu3.model.OperationOutcome;
|
||||||
|
import org.hl7.fhir.dstu3.model.Organization;
|
||||||
|
import org.hl7.fhir.dstu3.model.Parameters;
|
||||||
|
import org.hl7.fhir.dstu3.model.Patient;
|
||||||
|
import org.hl7.fhir.dstu3.model.Period;
|
||||||
|
import org.hl7.fhir.dstu3.model.Practitioner;
|
||||||
|
import org.hl7.fhir.dstu3.model.Questionnaire;
|
||||||
|
import org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemType;
|
||||||
|
import org.hl7.fhir.dstu3.model.QuestionnaireResponse;
|
||||||
|
import org.hl7.fhir.dstu3.model.Reference;
|
||||||
|
import org.hl7.fhir.dstu3.model.StringType;
|
||||||
|
import org.hl7.fhir.dstu3.model.Subscription;
|
||||||
|
import org.hl7.fhir.dstu3.model.Subscription.SubscriptionChannelType;
|
||||||
|
import org.hl7.fhir.dstu3.model.Subscription.SubscriptionStatus;
|
||||||
|
import org.hl7.fhir.dstu3.model.TemporalPrecisionEnum;
|
||||||
|
import org.hl7.fhir.dstu3.model.UnsignedIntType;
|
||||||
|
import org.hl7.fhir.dstu3.model.ValueSet;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||||
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
|
import ca.uhn.fhir.model.primitive.UriDt;
|
||||||
|
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||||
|
import ca.uhn.fhir.rest.api.SummaryEnum;
|
||||||
|
import ca.uhn.fhir.rest.client.IGenericClient;
|
||||||
|
import ca.uhn.fhir.rest.method.RequestDetails;
|
||||||
|
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||||
|
import ca.uhn.fhir.rest.param.ParamPrefixEnum;
|
||||||
|
import ca.uhn.fhir.rest.param.StringAndListParam;
|
||||||
|
import ca.uhn.fhir.rest.param.StringOrListParam;
|
||||||
|
import ca.uhn.fhir.rest.param.StringParam;
|
||||||
|
import ca.uhn.fhir.rest.param.TokenParam;
|
||||||
|
import ca.uhn.fhir.rest.server.Constants;
|
||||||
|
import ca.uhn.fhir.rest.server.IBundleProvider;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.ForbiddenOperationException;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||||
|
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||||
|
import ca.uhn.fhir.rest.server.interceptor.auth.AuthorizationInterceptor;
|
||||||
|
import ca.uhn.fhir.rest.server.interceptor.auth.IAuthRule;
|
||||||
|
import ca.uhn.fhir.rest.server.interceptor.auth.PolicyEnum;
|
||||||
|
import ca.uhn.fhir.rest.server.interceptor.auth.RuleBuilder;
|
||||||
|
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||||
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
|
import ca.uhn.fhir.util.UrlUtil;
|
||||||
|
|
||||||
|
public class AuthorizationInterceptorResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
|
||||||
|
|
||||||
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(AuthorizationInterceptorResourceProviderDstu3Test.class);
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void afterClassClearContext() {
|
||||||
|
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void before() throws Exception {
|
||||||
|
super.before();
|
||||||
|
myDaoConfig.setAllowMultipleDelete(true);
|
||||||
|
unregisterInterceptors();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void unregisterInterceptors() {
|
||||||
|
for (IServerInterceptor next : new ArrayList<IServerInterceptor>(ourRestServer.getInterceptors())) {
|
||||||
|
if (next instanceof AuthorizationInterceptor) {
|
||||||
|
ourRestServer.unregisterInterceptor(next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateConditional() {
|
||||||
|
|
||||||
|
Patient patient = new Patient();
|
||||||
|
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
|
||||||
|
patient.addName().addFamily("Tester").addGiven("Raghad");
|
||||||
|
final MethodOutcome output1 = ourClient.update().resource(patient).conditionalByUrl("Patient?identifier=http://uhn.ca/mrns|100").execute();
|
||||||
|
|
||||||
|
ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
||||||
|
@Override
|
||||||
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
|
//@formatter:off
|
||||||
|
return new RuleBuilder()
|
||||||
|
.allow("Rule 2").write().allResources().inCompartment("Patient", new IdDt("Patient/" + output1.getId().getIdPart())).andThen()
|
||||||
|
.build();
|
||||||
|
//@formatter:on
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
patient = new Patient();
|
||||||
|
patient.setId(output1.getId().toUnqualifiedVersionless());
|
||||||
|
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
|
||||||
|
patient.addName().addFamily("Tester").addGiven("Raghad");
|
||||||
|
MethodOutcome output2 = ourClient.update().resource(patient).conditionalByUrl("Patient?identifier=http://uhn.ca/mrns|100").execute();
|
||||||
|
|
||||||
|
assertEquals(output1.getId().getIdPart(), output2.getId().getIdPart());
|
||||||
|
|
||||||
|
patient = new Patient();
|
||||||
|
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
|
||||||
|
patient.addName().addFamily("Tester").addGiven("Raghad");
|
||||||
|
try {
|
||||||
|
ourClient.update().resource(patient).conditionalByUrl("Patient?identifier=http://uhn.ca/mrns|101").execute();
|
||||||
|
fail();
|
||||||
|
} catch (ForbiddenOperationException e) {
|
||||||
|
assertEquals("HTTP 403 Forbidden: Access denied by default policy (no applicable rules)", e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
patient = new Patient();
|
||||||
|
patient.setId("999");
|
||||||
|
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
|
||||||
|
patient.addName().addFamily("Tester").addGiven("Raghad");
|
||||||
|
try {
|
||||||
|
ourClient.update().resource(patient).execute();
|
||||||
|
fail();
|
||||||
|
} catch (ForbiddenOperationException e) {
|
||||||
|
assertEquals("HTTP 403 Forbidden: Access denied by default policy (no applicable rules)", e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteResourceConditional() throws IOException {
|
||||||
|
String methodName = "testDeleteResourceConditional";
|
||||||
|
|
||||||
|
Patient pt = new Patient();
|
||||||
|
pt.addName().addFamily(methodName);
|
||||||
|
String resource = myFhirCtx.newXmlParser().encodeResourceToString(pt);
|
||||||
|
|
||||||
|
HttpPost post = new HttpPost(ourServerBase + "/Patient");
|
||||||
|
post.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||||
|
CloseableHttpResponse response = ourHttpClient.execute(post);
|
||||||
|
final IdType id;
|
||||||
|
try {
|
||||||
|
assertEquals(201, response.getStatusLine().getStatusCode());
|
||||||
|
String newIdString = response.getFirstHeader(Constants.HEADER_LOCATION_LC).getValue();
|
||||||
|
assertThat(newIdString, startsWith(ourServerBase + "/Patient/"));
|
||||||
|
id = new IdType(newIdString);
|
||||||
|
} finally {
|
||||||
|
response.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
pt = new Patient();
|
||||||
|
pt.addName().addFamily("FOOFOOFOO");
|
||||||
|
resource = myFhirCtx.newXmlParser().encodeResourceToString(pt);
|
||||||
|
|
||||||
|
post = new HttpPost(ourServerBase + "/Patient");
|
||||||
|
post.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||||
|
response = ourHttpClient.execute(post);
|
||||||
|
final IdType id2;
|
||||||
|
try {
|
||||||
|
assertEquals(201, response.getStatusLine().getStatusCode());
|
||||||
|
String newIdString = response.getFirstHeader(Constants.HEADER_LOCATION_LC).getValue();
|
||||||
|
assertThat(newIdString, startsWith(ourServerBase + "/Patient/"));
|
||||||
|
id2 = new IdType(newIdString);
|
||||||
|
} finally {
|
||||||
|
response.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
||||||
|
@Override
|
||||||
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
|
//@formatter:off
|
||||||
|
return new RuleBuilder()
|
||||||
|
.allow("Rule 2").delete().allResources().inCompartment("Patient", new IdDt("Patient/" + id.getIdPart())).andThen()
|
||||||
|
.build();
|
||||||
|
//@formatter:on
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
HttpDelete delete = new HttpDelete(ourServerBase + "/Patient?name=" + methodName);
|
||||||
|
response = ourHttpClient.execute(delete);
|
||||||
|
try {
|
||||||
|
assertEquals(204, response.getStatusLine().getStatusCode());
|
||||||
|
} finally {
|
||||||
|
response.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
delete = new HttpDelete(ourServerBase + "/Patient?name=FOOFOOFOO");
|
||||||
|
response = ourHttpClient.execute(delete);
|
||||||
|
try {
|
||||||
|
assertEquals(403, response.getStatusLine().getStatusCode());
|
||||||
|
} finally {
|
||||||
|
response.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -42,6 +42,7 @@ import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Observation;
|
import ca.uhn.fhir.model.dstu2.resource.Observation;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||||
import ca.uhn.fhir.model.dstu2.valueset.BundleTypeEnum;
|
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.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.rest.annotation.Create;
|
import ca.uhn.fhir.rest.annotation.Create;
|
||||||
import ca.uhn.fhir.rest.annotation.Delete;
|
import ca.uhn.fhir.rest.annotation.Delete;
|
||||||
|
@ -152,7 +153,7 @@ public class AuthorizationInterceptorDstu2Test {
|
||||||
response = extractResponseAndClose(status);
|
response = extractResponseAndClose(status);
|
||||||
ourLog.info(response);
|
ourLog.info(response);
|
||||||
assertThat(response, containsString("Access denied by rule: Rule 1"));
|
assertThat(response, containsString("Access denied by rule: Rule 1"));
|
||||||
assertEquals(401, status.getStatusLine().getStatusCode());
|
assertEquals(403, status.getStatusLine().getStatusCode());
|
||||||
assertTrue(ourHitMethod);
|
assertTrue(ourHitMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,7 +190,7 @@ public class AuthorizationInterceptorDstu2Test {
|
||||||
response = extractResponseAndClose(status);
|
response = extractResponseAndClose(status);
|
||||||
ourLog.info(response);
|
ourLog.info(response);
|
||||||
assertThat(response, containsString("Access denied by rule: Default Rule"));
|
assertThat(response, containsString("Access denied by rule: Default Rule"));
|
||||||
assertEquals(401, status.getStatusLine().getStatusCode());
|
assertEquals(403, status.getStatusLine().getStatusCode());
|
||||||
assertTrue(ourHitMethod);
|
assertTrue(ourHitMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,8 +220,7 @@ public class AuthorizationInterceptorDstu2Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore // not done yet
|
public void testBatchWhenOnlyTransactionAllowed() throws Exception {
|
||||||
public void testBatchWhenTransactionAllowed() throws Exception {
|
|
||||||
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
|
@ -236,7 +236,7 @@ public class AuthorizationInterceptorDstu2Test {
|
||||||
|
|
||||||
Bundle input = new Bundle();
|
Bundle input = new Bundle();
|
||||||
input.setType(BundleTypeEnum.BATCH);
|
input.setType(BundleTypeEnum.BATCH);
|
||||||
input.addEntry().setResource(createPatient(1)).getRequest().setUrl("/Patient");
|
input.addEntry().setResource(createPatient(1)).getRequest().setUrl("/Patient").setMethod(HTTPVerbEnum.POST);
|
||||||
|
|
||||||
Bundle output = new Bundle();
|
Bundle output = new Bundle();
|
||||||
output.setType(BundleTypeEnum.TRANSACTION_RESPONSE);
|
output.setType(BundleTypeEnum.TRANSACTION_RESPONSE);
|
||||||
|
@ -252,7 +252,80 @@ public class AuthorizationInterceptorDstu2Test {
|
||||||
httpPost.setEntity(createFhirResourceEntity(input));
|
httpPost.setEntity(createFhirResourceEntity(input));
|
||||||
status = ourClient.execute(httpPost);
|
status = ourClient.execute(httpPost);
|
||||||
extractResponseAndClose(status);
|
extractResponseAndClose(status);
|
||||||
assertEquals(401, status.getStatusLine().getStatusCode());
|
assertEquals(403, status.getStatusLine().getStatusCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBatchWhenTransactionReadDenied() throws Exception {
|
||||||
|
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
||||||
|
@Override
|
||||||
|
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()
|
||||||
|
.build();
|
||||||
|
//@formatter:on
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Bundle input = new Bundle();
|
||||||
|
input.setType(BundleTypeEnum.BATCH);
|
||||||
|
input.addEntry().setResource(createPatient(1)).getRequest().setUrl("/Patient").setMethod(HTTPVerbEnum.POST);
|
||||||
|
|
||||||
|
Bundle output = new Bundle();
|
||||||
|
output.setType(BundleTypeEnum.TRANSACTION_RESPONSE);
|
||||||
|
output.addEntry().setResource(createPatient(2));
|
||||||
|
|
||||||
|
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(403, status.getStatusLine().getStatusCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBatchWhenTransactionWrongBundleType() throws Exception {
|
||||||
|
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
||||||
|
@Override
|
||||||
|
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()
|
||||||
|
.build();
|
||||||
|
//@formatter:on
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Bundle input = new Bundle();
|
||||||
|
input.setType(BundleTypeEnum.COLLECTION);
|
||||||
|
input.addEntry().setResource(createPatient(1)).getRequest().setUrl("/Patient").setMethod(HTTPVerbEnum.POST);
|
||||||
|
|
||||||
|
Bundle output = new Bundle();
|
||||||
|
output.setType(BundleTypeEnum.TRANSACTION_RESPONSE);
|
||||||
|
output.addEntry().setResource(createPatient(1));
|
||||||
|
|
||||||
|
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);
|
||||||
|
response = extractResponseAndClose(status);
|
||||||
|
assertEquals(403, status.getStatusLine().getStatusCode());
|
||||||
|
assertThat(response, containsString("Invalid transaction bundle type: collection"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -277,7 +350,7 @@ public class AuthorizationInterceptorDstu2Test {
|
||||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/metadata");
|
httpGet = new HttpGet("http://localhost:" + ourPort + "/metadata");
|
||||||
status = ourClient.execute(httpGet);
|
status = ourClient.execute(httpGet);
|
||||||
extractResponseAndClose(status);
|
extractResponseAndClose(status);
|
||||||
assertEquals(401, status.getStatusLine().getStatusCode());
|
assertEquals(403, status.getStatusLine().getStatusCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -312,7 +385,7 @@ public class AuthorizationInterceptorDstu2Test {
|
||||||
response = extractResponseAndClose(status);
|
response = extractResponseAndClose(status);
|
||||||
ourLog.info(response);
|
ourLog.info(response);
|
||||||
assertThat(response, containsString("Access denied by default policy (no applicable rules)"));
|
assertThat(response, containsString("Access denied by default policy (no applicable rules)"));
|
||||||
assertEquals(401, status.getStatusLine().getStatusCode());
|
assertEquals(403, status.getStatusLine().getStatusCode());
|
||||||
assertTrue(ourHitMethod);
|
assertTrue(ourHitMethod);
|
||||||
|
|
||||||
ourReturn = Arrays.asList(createPatient(1), createObservation(10, "Patient/2"));
|
ourReturn = Arrays.asList(createPatient(1), createObservation(10, "Patient/2"));
|
||||||
|
@ -322,7 +395,7 @@ public class AuthorizationInterceptorDstu2Test {
|
||||||
response = extractResponseAndClose(status);
|
response = extractResponseAndClose(status);
|
||||||
ourLog.info(response);
|
ourLog.info(response);
|
||||||
assertThat(response, containsString("Access denied by default policy (no applicable rules)"));
|
assertThat(response, containsString("Access denied by default policy (no applicable rules)"));
|
||||||
assertEquals(401, status.getStatusLine().getStatusCode());
|
assertEquals(403, status.getStatusLine().getStatusCode());
|
||||||
assertTrue(ourHitMethod);
|
assertTrue(ourHitMethod);
|
||||||
|
|
||||||
ourReturn = Arrays.asList(createPatient(2), createObservation(10, "Patient/1"));
|
ourReturn = Arrays.asList(createPatient(2), createObservation(10, "Patient/1"));
|
||||||
|
@ -332,7 +405,7 @@ public class AuthorizationInterceptorDstu2Test {
|
||||||
response = extractResponseAndClose(status);
|
response = extractResponseAndClose(status);
|
||||||
ourLog.info(response);
|
ourLog.info(response);
|
||||||
assertThat(response, containsString("Access denied by default policy (no applicable rules)"));
|
assertThat(response, containsString("Access denied by default policy (no applicable rules)"));
|
||||||
assertEquals(401, status.getStatusLine().getStatusCode());
|
assertEquals(403, status.getStatusLine().getStatusCode());
|
||||||
assertTrue(ourHitMethod);
|
assertTrue(ourHitMethod);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -405,7 +478,7 @@ public class AuthorizationInterceptorDstu2Test {
|
||||||
response = extractResponseAndClose(status);
|
response = extractResponseAndClose(status);
|
||||||
ourLog.info(response);
|
ourLog.info(response);
|
||||||
assertThat(response, containsString("Access denied by default policy (no applicable rules)"));
|
assertThat(response, containsString("Access denied by default policy (no applicable rules)"));
|
||||||
assertEquals(401, status.getStatusLine().getStatusCode());
|
assertEquals(403, status.getStatusLine().getStatusCode());
|
||||||
assertTrue(ourHitMethod);
|
assertTrue(ourHitMethod);
|
||||||
|
|
||||||
ourReturn = Arrays.asList(createObservation(10, "Patient/2"));
|
ourReturn = Arrays.asList(createObservation(10, "Patient/2"));
|
||||||
|
@ -415,7 +488,7 @@ public class AuthorizationInterceptorDstu2Test {
|
||||||
response = extractResponseAndClose(status);
|
response = extractResponseAndClose(status);
|
||||||
ourLog.info(response);
|
ourLog.info(response);
|
||||||
assertThat(response, containsString("Access denied by default policy (no applicable rules)"));
|
assertThat(response, containsString("Access denied by default policy (no applicable rules)"));
|
||||||
assertEquals(401, status.getStatusLine().getStatusCode());
|
assertEquals(403, status.getStatusLine().getStatusCode());
|
||||||
assertTrue(ourHitMethod);
|
assertTrue(ourHitMethod);
|
||||||
|
|
||||||
ourReturn = Arrays.asList(createPatient(1), createObservation(10, "Patient/2"));
|
ourReturn = Arrays.asList(createPatient(1), createObservation(10, "Patient/2"));
|
||||||
|
@ -425,7 +498,7 @@ public class AuthorizationInterceptorDstu2Test {
|
||||||
response = extractResponseAndClose(status);
|
response = extractResponseAndClose(status);
|
||||||
ourLog.info(response);
|
ourLog.info(response);
|
||||||
assertThat(response, containsString("Access denied by default policy (no applicable rules)"));
|
assertThat(response, containsString("Access denied by default policy (no applicable rules)"));
|
||||||
assertEquals(401, status.getStatusLine().getStatusCode());
|
assertEquals(403, status.getStatusLine().getStatusCode());
|
||||||
assertTrue(ourHitMethod);
|
assertTrue(ourHitMethod);
|
||||||
|
|
||||||
ourReturn = Arrays.asList(createPatient(2), createObservation(10, "Patient/1"));
|
ourReturn = Arrays.asList(createPatient(2), createObservation(10, "Patient/1"));
|
||||||
|
@ -435,7 +508,7 @@ public class AuthorizationInterceptorDstu2Test {
|
||||||
response = extractResponseAndClose(status);
|
response = extractResponseAndClose(status);
|
||||||
ourLog.info(response);
|
ourLog.info(response);
|
||||||
assertThat(response, containsString("Access denied by default policy (no applicable rules)"));
|
assertThat(response, containsString("Access denied by default policy (no applicable rules)"));
|
||||||
assertEquals(401, status.getStatusLine().getStatusCode());
|
assertEquals(403, status.getStatusLine().getStatusCode());
|
||||||
assertTrue(ourHitMethod);
|
assertTrue(ourHitMethod);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -458,7 +531,7 @@ public class AuthorizationInterceptorDstu2Test {
|
||||||
|
|
||||||
Bundle input = new Bundle();
|
Bundle input = new Bundle();
|
||||||
input.setType(BundleTypeEnum.TRANSACTION);
|
input.setType(BundleTypeEnum.TRANSACTION);
|
||||||
input.addEntry().setResource(createPatient(1)).getRequest().setUrl("/Patient");
|
input.addEntry().setResource(createPatient(1)).getRequest().setUrl("/Patient").setMethod(HTTPVerbEnum.PUT);
|
||||||
|
|
||||||
Bundle output = new Bundle();
|
Bundle output = new Bundle();
|
||||||
output.setType(BundleTypeEnum.TRANSACTION_RESPONSE);
|
output.setType(BundleTypeEnum.TRANSACTION_RESPONSE);
|
||||||
|
@ -500,7 +573,7 @@ public class AuthorizationInterceptorDstu2Test {
|
||||||
status = ourClient.execute(httpPost);
|
status = ourClient.execute(httpPost);
|
||||||
String response = extractResponseAndClose(status);
|
String response = extractResponseAndClose(status);
|
||||||
assertEquals("Access denied by default policy (no applicable rules)", response);
|
assertEquals("Access denied by default policy (no applicable rules)", response);
|
||||||
assertEquals(401, status.getStatusLine().getStatusCode());
|
assertEquals(403, status.getStatusLine().getStatusCode());
|
||||||
assertFalse(ourHitMethod);
|
assertFalse(ourHitMethod);
|
||||||
|
|
||||||
ourHitMethod = false;
|
ourHitMethod = false;
|
||||||
|
@ -509,7 +582,7 @@ public class AuthorizationInterceptorDstu2Test {
|
||||||
status = ourClient.execute(httpPost);
|
status = ourClient.execute(httpPost);
|
||||||
response = extractResponseAndClose(status);
|
response = extractResponseAndClose(status);
|
||||||
assertEquals("Access denied by default policy (no applicable rules)", response);
|
assertEquals("Access denied by default policy (no applicable rules)", response);
|
||||||
assertEquals(401, status.getStatusLine().getStatusCode());
|
assertEquals(403, status.getStatusLine().getStatusCode());
|
||||||
assertFalse(ourHitMethod);
|
assertFalse(ourHitMethod);
|
||||||
|
|
||||||
ourHitMethod = false;
|
ourHitMethod = false;
|
||||||
|
@ -543,7 +616,7 @@ public class AuthorizationInterceptorDstu2Test {
|
||||||
httpDelete = new HttpDelete("http://localhost:" + ourPort + "/Patient/2");
|
httpDelete = new HttpDelete("http://localhost:" + ourPort + "/Patient/2");
|
||||||
status = ourClient.execute(httpDelete);
|
status = ourClient.execute(httpDelete);
|
||||||
extractResponseAndClose(status);
|
extractResponseAndClose(status);
|
||||||
assertEquals(401, status.getStatusLine().getStatusCode());
|
assertEquals(403, status.getStatusLine().getStatusCode());
|
||||||
assertTrue(ourHitMethod);
|
assertTrue(ourHitMethod);
|
||||||
|
|
||||||
ourHitMethod = false;
|
ourHitMethod = false;
|
||||||
|
@ -578,7 +651,7 @@ public class AuthorizationInterceptorDstu2Test {
|
||||||
status = ourClient.execute(httpPost);
|
status = ourClient.execute(httpPost);
|
||||||
String response = extractResponseAndClose(status);
|
String response = extractResponseAndClose(status);
|
||||||
assertEquals("Access denied by default policy (no applicable rules)", response);
|
assertEquals("Access denied by default policy (no applicable rules)", response);
|
||||||
assertEquals(401, status.getStatusLine().getStatusCode());
|
assertEquals(403, status.getStatusLine().getStatusCode());
|
||||||
assertFalse(ourHitMethod);
|
assertFalse(ourHitMethod);
|
||||||
|
|
||||||
ourHitMethod = false;
|
ourHitMethod = false;
|
||||||
|
@ -603,10 +676,12 @@ public class AuthorizationInterceptorDstu2Test {
|
||||||
status = ourClient.execute(httpPost);
|
status = ourClient.execute(httpPost);
|
||||||
response = extractResponseAndClose(status);
|
response = extractResponseAndClose(status);
|
||||||
assertEquals("Access denied by default policy (no applicable rules)", response);
|
assertEquals("Access denied by default policy (no applicable rules)", response);
|
||||||
assertEquals(401, status.getStatusLine().getStatusCode());
|
assertEquals(403, status.getStatusLine().getStatusCode());
|
||||||
assertFalse(ourHitMethod);
|
assertFalse(ourHitMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
public static void afterClassClearContext() throws Exception {
|
public static void afterClassClearContext() throws Exception {
|
||||||
|
|
Loading…
Reference in New Issue