Allow AuthorizationInterceptor to read patients if the user has read
access to the individual instance
This commit is contained in:
parent
4f5640e541
commit
b8755615b2
|
@ -13,9 +13,9 @@ import java.util.Collection;
|
|||
* 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.
|
||||
|
@ -32,14 +32,14 @@ public interface IAuthRuleBuilderRuleOp extends IAuthRuleBuilderAppliesTo<IAuthR
|
|||
* See the following examples which show how theId is interpreted:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li><b><code>http://example.com/Patient/123</code></b> - Any Patient resource with the ID "123" will be matched (note: the base URL part is ignored)</li>
|
||||
* <li><b><code>http://example.com/Patient/123</code></b> - Any Patient resource with the ID "123" will be matched (note: the base URL part is ignored)</li>
|
||||
* <li><b><code>Patient/123</code></b> - Any Patient resource with the ID "123" will be matched</li>
|
||||
* <li><b><code>123</code></b> - Any resource of any type with the ID "123" will be matched</li>
|
||||
* </ul>
|
||||
*
|
||||
*
|
||||
* @param theId The ID of the resource to apply (e.g. <code>Patient/123</code>)
|
||||
* @throws IllegalArgumentException If theId does not contain an ID with at least an ID part
|
||||
* @throws NullPointerException If theId is null
|
||||
* @throws NullPointerException If theId is null
|
||||
*/
|
||||
IAuthRuleFinished instance(String theId);
|
||||
|
||||
|
@ -49,16 +49,31 @@ public interface IAuthRuleBuilderRuleOp extends IAuthRuleBuilderAppliesTo<IAuthR
|
|||
* See the following examples which show how theId is interpreted:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li><b><code>http://example.com/Patient/123</code></b> - Any Patient resource with the ID "123" will be matched (note: the base URL part is ignored)</li>
|
||||
* <li><b><code>http://example.com/Patient/123</code></b> - Any Patient resource with the ID "123" will be matched (note: the base URL part is ignored)</li>
|
||||
* <li><b><code>Patient/123</code></b> - Any Patient resource with the ID "123" will be matched</li>
|
||||
* <li><b><code>123</code></b> - Any resource of any type with the ID "123" will be matched</li>
|
||||
* </ul>
|
||||
*
|
||||
*
|
||||
* @param theId The ID of the resource to apply (e.g. <code>Patient/123</code>)
|
||||
* @throws IllegalArgumentException If theId does not contain an ID with at least an ID part
|
||||
* @throws NullPointerException If theId is null
|
||||
* @throws NullPointerException If theId is null
|
||||
*/
|
||||
IAuthRuleFinished instance(IIdType theId);
|
||||
|
||||
IAuthRuleFinished instances(Collection<IIdType> theInstances);
|
||||
/**
|
||||
* Rule applies to the resource with the given ID (e.g. <code>Patient/123</code>)
|
||||
* <p>
|
||||
* See the following examples which show how theId is interpreted:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li><b><code>http://example.com/Patient/123</code></b> - Any Patient resource with the ID "123" will be matched (note: the base URL part is ignored)</li>
|
||||
* <li><b><code>Patient/123</code></b> - Any Patient resource with the ID "123" will be matched</li>
|
||||
* <li><b><code>123</code></b> - Any resource of any type with the ID "123" will be matched</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param theIds The IDs of the resource to apply (e.g. <code>Patient/123</code>)
|
||||
* @throws IllegalArgumentException If theId does not contain an ID with at least an ID part
|
||||
* @throws NullPointerException If theId is null
|
||||
*/
|
||||
IAuthRuleFinished instances(Collection<IIdType> theIds);
|
||||
}
|
||||
|
|
|
@ -9,9 +9,9 @@ package ca.uhn.fhir.rest.server.interceptor.auth;
|
|||
* 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.
|
||||
|
@ -23,6 +23,7 @@ package ca.uhn.fhir.rest.server.interceptor.auth;
|
|||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
|
@ -35,6 +36,8 @@ public class RuleBuilder implements IAuthRuleBuilder {
|
|||
|
||||
private static final String[] EMPTY_STRING_ARRAY = new String[0];
|
||||
private ArrayList<IAuthRule> myRules;
|
||||
private IAuthRuleBuilderRule myAllow;
|
||||
private IAuthRuleBuilderRule myDeny;
|
||||
|
||||
public RuleBuilder() {
|
||||
myRules = new ArrayList<>();
|
||||
|
@ -42,7 +45,10 @@ public class RuleBuilder implements IAuthRuleBuilder {
|
|||
|
||||
@Override
|
||||
public IAuthRuleBuilderRule allow() {
|
||||
return allow(null);
|
||||
if (myAllow == null) {
|
||||
myAllow = allow(null);
|
||||
}
|
||||
return myAllow;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -69,7 +75,10 @@ public class RuleBuilder implements IAuthRuleBuilder {
|
|||
|
||||
@Override
|
||||
public IAuthRuleBuilderRule deny() {
|
||||
return deny(null);
|
||||
if (myDeny == null) {
|
||||
myDeny = deny(null);
|
||||
}
|
||||
return myDeny;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -153,7 +162,7 @@ public class RuleBuilder implements IAuthRuleBuilder {
|
|||
|
||||
private void setTenantApplicabilityChecker(ITenantApplicabilityChecker theTenantApplicabilityChecker) {
|
||||
myTenantApplicabilityChecker = theTenantApplicabilityChecker;
|
||||
myOpRule.setTenantApplicabilityChecker(myTenantApplicabilityChecker);
|
||||
myOpRule.setTenantApplicabilityChecker(myTenantApplicabilityChecker);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -172,6 +181,8 @@ public class RuleBuilder implements IAuthRuleBuilder {
|
|||
|
||||
private PolicyEnum myRuleMode;
|
||||
private String myRuleName;
|
||||
private RuleBuilderRuleOp myReadRuleBuilder;
|
||||
private RuleBuilderRuleOp myWriteRuleBuilder;
|
||||
|
||||
RuleBuilderRule(PolicyEnum theRuleMode, String theRuleName) {
|
||||
myRuleMode = theRuleMode;
|
||||
|
@ -214,7 +225,10 @@ public class RuleBuilder implements IAuthRuleBuilder {
|
|||
|
||||
@Override
|
||||
public IAuthRuleBuilderRuleOp read() {
|
||||
return new RuleBuilderRuleOp(RuleOpEnum.READ);
|
||||
if (myReadRuleBuilder == null) {
|
||||
myReadRuleBuilder = new RuleBuilderRuleOp(RuleOpEnum.READ);
|
||||
}
|
||||
return myReadRuleBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -229,7 +243,10 @@ public class RuleBuilder implements IAuthRuleBuilder {
|
|||
|
||||
@Override
|
||||
public IAuthRuleBuilderRuleOp write() {
|
||||
return new RuleBuilderRuleOp(RuleOpEnum.WRITE);
|
||||
if (myWriteRuleBuilder == null) {
|
||||
myWriteRuleBuilder = new RuleBuilderRuleOp(RuleOpEnum.WRITE);
|
||||
}
|
||||
return myWriteRuleBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -286,6 +303,7 @@ public class RuleBuilder implements IAuthRuleBuilder {
|
|||
private class RuleBuilderRuleOp implements IAuthRuleBuilderRuleOp {
|
||||
|
||||
private final RuleOpEnum myRuleOp;
|
||||
private RuleBuilderRuleOpClassifier myInstancesBuilder;
|
||||
|
||||
public RuleBuilderRuleOp(RuleOpEnum theRuleOp) {
|
||||
myRuleOp = theRuleOp;
|
||||
|
@ -308,16 +326,22 @@ public class RuleBuilder implements IAuthRuleBuilder {
|
|||
Validate.notBlank(theId.getValue(), "theId.getValue() must not be null or empty");
|
||||
Validate.notBlank(theId.getIdPart(), "theId must contain an ID part");
|
||||
|
||||
List<IIdType> instances = Collections.singletonList(theId);
|
||||
List<IIdType> instances = Lists.newArrayList(theId);
|
||||
return instances(instances);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAuthRuleFinished instances(Collection<IIdType> theInstances) {
|
||||
public RuleBuilderFinished instances(Collection<IIdType> theInstances) {
|
||||
Validate.notNull(theInstances, "theInstances must not be null");
|
||||
Validate.notEmpty(theInstances, "theInstances must not be empty");
|
||||
|
||||
return new RuleBuilderRuleOpClassifier(theInstances).finished();
|
||||
if (myInstancesBuilder == null) {
|
||||
RuleBuilderRuleOpClassifier instancesBuilder = new RuleBuilderRuleOpClassifier(theInstances);
|
||||
myInstancesBuilder = instancesBuilder;
|
||||
return instancesBuilder.finished();
|
||||
} else {
|
||||
return myInstancesBuilder.addInstances(theInstances);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -328,12 +352,13 @@ public class RuleBuilder implements IAuthRuleBuilder {
|
|||
|
||||
private class RuleBuilderRuleOpClassifier implements IAuthRuleBuilderRuleOpClassifier {
|
||||
|
||||
private final AppliesTypeEnum myAppliesTo;
|
||||
private final Set<?> myAppliesToTypes;
|
||||
private ClassifierTypeEnum myClassifierType;
|
||||
private String myInCompartmentName;
|
||||
private Collection<? extends IIdType> myInCompartmentOwners;
|
||||
private Collection<IIdType> myAppliesToInstances;
|
||||
private final AppliesTypeEnum myAppliesTo;
|
||||
private final Set<?> myAppliesToTypes;
|
||||
private RuleImplOp myRule;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -341,7 +366,7 @@ public class RuleBuilder implements IAuthRuleBuilder {
|
|||
RuleBuilderRuleOpClassifier(AppliesTypeEnum theAppliesTo, Set<Class<? extends IBaseResource>> theAppliesToTypes) {
|
||||
super();
|
||||
myAppliesTo = theAppliesTo;
|
||||
myAppliesToTypes=theAppliesToTypes;
|
||||
myAppliesToTypes = theAppliesToTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -353,20 +378,20 @@ public class RuleBuilder implements IAuthRuleBuilder {
|
|||
myAppliesToTypes = null;
|
||||
}
|
||||
|
||||
private IAuthRuleBuilderRuleOpClassifierFinished finished() {
|
||||
private RuleBuilderFinished finished() {
|
||||
Validate.isTrue(myRule == null, "Can not call finished() twice");
|
||||
myRule = new RuleImplOp(myRuleName);
|
||||
myRule.setMode(myRuleMode);
|
||||
myRule.setOp(myRuleOp);
|
||||
myRule.setAppliesTo(myAppliesTo);
|
||||
myRule.setAppliesToTypes(myAppliesToTypes);
|
||||
myRule.setAppliesToInstances(myAppliesToInstances);
|
||||
myRule.setClassifierType(myClassifierType);
|
||||
myRule.setClassifierCompartmentName(myInCompartmentName);
|
||||
myRule.setClassifierCompartmentOwners(myInCompartmentOwners);
|
||||
myRules.add(myRule);
|
||||
|
||||
RuleImplOp rule = new RuleImplOp(myRuleName);
|
||||
rule.setMode(myRuleMode);
|
||||
rule.setOp(myRuleOp);
|
||||
rule.setAppliesTo(myAppliesTo);
|
||||
rule.setAppliesToTypes(myAppliesToTypes);
|
||||
rule.setAppliesToInstances(myAppliesToInstances);
|
||||
rule.setClassifierType(myClassifierType);
|
||||
rule.setClassifierCompartmentName(myInCompartmentName);
|
||||
rule.setClassifierCompartmentOwners(myInCompartmentOwners);
|
||||
myRules.add(rule);
|
||||
|
||||
return new RuleBuilderFinished(rule);
|
||||
return new RuleBuilderFinished(myRule);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -405,6 +430,10 @@ public class RuleBuilder implements IAuthRuleBuilder {
|
|||
return finished();
|
||||
}
|
||||
|
||||
RuleBuilderFinished addInstances(Collection<IIdType> theInstances) {
|
||||
myAppliesToInstances.addAll(theInstances);
|
||||
return new RuleBuilderFinished(myRule);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -424,28 +453,6 @@ public class RuleBuilder implements IAuthRuleBuilder {
|
|||
|
||||
private class RuleBuilderRuleOperationNamed implements IAuthRuleBuilderOperationNamed {
|
||||
|
||||
private class RuleBuilderOperationNamedAndScoped implements IAuthRuleBuilderOperationNamedAndScoped {
|
||||
|
||||
private final OperationRule myRule;
|
||||
|
||||
public RuleBuilderOperationNamedAndScoped(OperationRule theRule) {
|
||||
myRule = theRule;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAuthRuleBuilderRuleOpClassifierFinished andAllowAllResponses() {
|
||||
myRule.allowAllResponses();
|
||||
myRules.add(myRule);
|
||||
return new RuleBuilderFinished(myRule);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAuthRuleBuilderRuleOpClassifierFinished andRequireExplicitResponseAuthorization() {
|
||||
myRules.add(myRule);
|
||||
return new RuleBuilderFinished(myRule);
|
||||
}
|
||||
}
|
||||
|
||||
private String myOperationName;
|
||||
|
||||
RuleBuilderRuleOperationNamed(String theOperationName) {
|
||||
|
@ -532,6 +539,28 @@ public class RuleBuilder implements IAuthRuleBuilder {
|
|||
Validate.notNull(theType, "theType must not be null");
|
||||
}
|
||||
|
||||
private class RuleBuilderOperationNamedAndScoped implements IAuthRuleBuilderOperationNamedAndScoped {
|
||||
|
||||
private final OperationRule myRule;
|
||||
|
||||
public RuleBuilderOperationNamedAndScoped(OperationRule theRule) {
|
||||
myRule = theRule;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAuthRuleBuilderRuleOpClassifierFinished andAllowAllResponses() {
|
||||
myRule.allowAllResponses();
|
||||
myRules.add(myRule);
|
||||
return new RuleBuilderFinished(myRule);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAuthRuleBuilderRuleOpClassifierFinished andRequireExplicitResponseAuthorization() {
|
||||
myRules.add(myRule);
|
||||
return new RuleBuilderFinished(myRule);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,15 +3,18 @@ package ca.uhn.fhir.rest.server.interceptor.auth;
|
|||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.rest.api.QualifiedParamList;
|
||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.param.ParameterUtil;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.rest.server.interceptor.auth.AuthorizationInterceptor.Verdict;
|
||||
import ca.uhn.fhir.util.BundleUtil;
|
||||
import ca.uhn.fhir.util.BundleUtil.BundleEntryParts;
|
||||
import ca.uhn.fhir.util.FhirTerser;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
@ -34,9 +37,9 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
|||
* 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.
|
||||
|
@ -64,6 +67,15 @@ class RuleImplOp extends BaseRule /* implements IAuthRule */ {
|
|||
super(theRuleName);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
Collection<IIdType> getAppliesToInstances() {
|
||||
return myAppliesToInstances;
|
||||
}
|
||||
|
||||
public void setAppliesToInstances(Collection<IIdType> theAppliesToInstances) {
|
||||
myAppliesToInstances = theAppliesToInstances;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Verdict applyRule(RestOperationTypeEnum theOperation, RequestDetails theRequestDetails, IBaseResource theInputResource, IIdType theInputResourceId, IBaseResource theOutputResource,
|
||||
IRuleApplier theRuleApplier, Set<AuthorizationFlagsEnum> theFlags) {
|
||||
|
@ -111,14 +123,18 @@ class RuleImplOp extends BaseRule /* implements IAuthRule */ {
|
|||
if (theRequestDetails.getParameters().containsKey("_id")) {
|
||||
String[] idValues = theRequestDetails.getParameters().get("_id");
|
||||
appliesToResourceId = new ArrayList<>();
|
||||
for (String next : idValues) {
|
||||
IIdType nextId = ctx.getVersion().newIdType().setValue(next);
|
||||
if (nextId.hasIdPart()){
|
||||
if (!nextId.hasResourceType()) {
|
||||
nextId = nextId.withResourceType(appliesToResourceType);
|
||||
}
|
||||
if (nextId.getResourceType().equals(appliesToResourceType)) {
|
||||
appliesToResourceId.add(nextId);
|
||||
|
||||
for (String nextIdValue : idValues) {
|
||||
QualifiedParamList orParamList = QualifiedParamList.splitQueryStringByCommasIgnoreEscape(null, nextIdValue);
|
||||
for (String next : orParamList) {
|
||||
IIdType nextId = ctx.getVersion().newIdType().setValue(next);
|
||||
if (nextId.hasIdPart()) {
|
||||
if (!nextId.hasResourceType()) {
|
||||
nextId = nextId.withResourceType(appliesToResourceType);
|
||||
}
|
||||
if (nextId.getResourceType().equals(appliesToResourceType)) {
|
||||
appliesToResourceId.add(nextId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -340,6 +356,7 @@ class RuleImplOp extends BaseRule /* implements IAuthRule */ {
|
|||
return newVerdict();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
case ALL_RESOURCES:
|
||||
if (appliesToResourceType != null) {
|
||||
|
@ -531,10 +548,6 @@ class RuleImplOp extends BaseRule /* implements IAuthRule */ {
|
|||
myAppliesTo = theAppliesTo;
|
||||
}
|
||||
|
||||
public void setAppliesToInstances(Collection<IIdType> theAppliesToInstances) {
|
||||
myAppliesToInstances = theAppliesToInstances;
|
||||
}
|
||||
|
||||
public void setAppliesToTypes(Set<?> theAppliesToTypes) {
|
||||
myAppliesToTypes = theAppliesToTypes;
|
||||
}
|
||||
|
|
|
@ -1,14 +1,51 @@
|
|||
package ca.uhn.fhir.rest.server.interceptor.auth;
|
||||
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class RuleBuilderTest {
|
||||
|
||||
/**
|
||||
* If the user creates multiple rules that allow read/write of individual
|
||||
* instances, we will collapse these into a single rule for performance
|
||||
*/
|
||||
@Test
|
||||
public void testCollapseReadInstancesIntoSingleRule() {
|
||||
RuleBuilder builder = new RuleBuilder();
|
||||
builder.allow().read().instance(new IdDt("Patient/READ-1"));
|
||||
builder.allow().write().instance(new IdDt("Patient/WRITE-1"));
|
||||
builder.allow().read().instance(new IdDt("Patient/READ-2"));
|
||||
builder.allow().write().instance(new IdDt("Patient/WRITE-2"));
|
||||
builder.allow().read().instances(Lists.newArrayList(new IdDt("Patient/READ-3"), new IdDt("Patient/READ-4")));
|
||||
builder.allow().write().instances(Lists.newArrayList(new IdDt("Patient/WRITE-3"), new IdDt("Patient/WRITE-4")));
|
||||
List<IAuthRule> list = builder.build();
|
||||
|
||||
assertEquals(2, list.size());
|
||||
|
||||
assertEquals(RuleImplOp.class, list.get(0).getClass());
|
||||
RuleImplOp allowRead = (RuleImplOp) list.get(0);
|
||||
assertThat(allowRead.getAppliesToInstances(), contains(
|
||||
new IdDt("Patient/READ-1"),
|
||||
new IdDt("Patient/READ-2"),
|
||||
new IdDt("Patient/READ-3"),
|
||||
new IdDt("Patient/READ-4")
|
||||
));
|
||||
|
||||
assertEquals(RuleImplOp.class, list.get(1).getClass());
|
||||
RuleImplOp allowWrite = (RuleImplOp) list.get(1);
|
||||
assertThat(allowWrite.getAppliesToInstances(), contains(
|
||||
new IdDt("Patient/WRITE-1"),
|
||||
new IdDt("Patient/WRITE-2"),
|
||||
new IdDt("Patient/WRITE-3"),
|
||||
new IdDt("Patient/WRITE-4")
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2507,10 +2507,10 @@ public class AuthorizationInterceptorDstu3Test {
|
|||
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
||||
@Override
|
||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||
return new RuleBuilder()
|
||||
.allow("Rule 1").read().instance("Patient/900").andThen()
|
||||
.allow("Rule 1").read().instance("Patient/700").andThen()
|
||||
.build();
|
||||
RuleBuilder ruleBuilder = new RuleBuilder();
|
||||
ruleBuilder.allow().read().instance("Patient/900").andThen();
|
||||
ruleBuilder.allow().read().instance("Patient/700").andThen();
|
||||
return ruleBuilder.build();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -2519,51 +2519,65 @@ public class AuthorizationInterceptorDstu3Test {
|
|||
HttpGet httpGet;
|
||||
ourReturn = Collections.singletonList(createPatient(900));
|
||||
|
||||
// ourHitMethod = false;
|
||||
// httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_id=900");
|
||||
// status = ourClient.execute(httpGet);
|
||||
// extractResponseAndClose(status);
|
||||
// assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
// assertTrue(ourHitMethod);
|
||||
//
|
||||
// ourHitMethod = false;
|
||||
// httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_id=Patient/900");
|
||||
// status = ourClient.execute(httpGet);
|
||||
// extractResponseAndClose(status);
|
||||
// assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
// assertTrue(ourHitMethod);
|
||||
//
|
||||
// ourHitMethod = false;
|
||||
// httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_id=901");
|
||||
// status = ourClient.execute(httpGet);
|
||||
// response = extractResponseAndClose(status);
|
||||
// assertEquals(403, status.getStatusLine().getStatusCode());
|
||||
// assertEquals(ERR403, response);
|
||||
// assertFalse(ourHitMethod);
|
||||
//
|
||||
// ourHitMethod = false;
|
||||
// httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_id=Patient/901");
|
||||
// status = ourClient.execute(httpGet);
|
||||
// response = extractResponseAndClose(status);
|
||||
// assertEquals(403, status.getStatusLine().getStatusCode());
|
||||
// assertEquals(ERR403, response);
|
||||
// assertFalse(ourHitMethod);
|
||||
//
|
||||
// ourHitMethod = false;
|
||||
// // technically this is invalid, but just in case..
|
||||
// httpGet = new HttpGet("http://localhost:" + ourPort + "/Observation?_id=Patient/901");
|
||||
// status = ourClient.execute(httpGet);
|
||||
// response = extractResponseAndClose(status);
|
||||
// assertEquals(403, status.getStatusLine().getStatusCode());
|
||||
// assertEquals(ERR403, response);
|
||||
// assertFalse(ourHitMethod);
|
||||
//
|
||||
// ourHitMethod = false;
|
||||
// httpGet = new HttpGet("http://localhost:" + ourPort + "/Observation?_id=901");
|
||||
// status = ourClient.execute(httpGet);
|
||||
// response = extractResponseAndClose(status);
|
||||
// assertEquals(403, status.getStatusLine().getStatusCode());
|
||||
// assertEquals(ERR403, response);
|
||||
// assertFalse(ourHitMethod);
|
||||
|
||||
ourHitMethod = false;
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_id=900");
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_id=Patient/900,Patient/700");
|
||||
status = ourClient.execute(httpGet);
|
||||
extractResponseAndClose(status);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertTrue(ourHitMethod);
|
||||
|
||||
ourHitMethod = false;
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_id=Patient/900");
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_id=900,777");
|
||||
status = ourClient.execute(httpGet);
|
||||
extractResponseAndClose(status);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertTrue(ourHitMethod);
|
||||
|
||||
ourHitMethod = false;
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_id=901");
|
||||
status = ourClient.execute(httpGet);
|
||||
response = extractResponseAndClose(status);
|
||||
assertEquals(403, status.getStatusLine().getStatusCode());
|
||||
assertEquals(ERR403, response);
|
||||
assertFalse(ourHitMethod);
|
||||
|
||||
ourHitMethod = false;
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_id=Patient/901");
|
||||
status = ourClient.execute(httpGet);
|
||||
response = extractResponseAndClose(status);
|
||||
assertEquals(403, status.getStatusLine().getStatusCode());
|
||||
assertEquals(ERR403, response);
|
||||
assertFalse(ourHitMethod);
|
||||
|
||||
ourHitMethod = false;
|
||||
// technically this is invalid, but just in case..
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Observation?_id=Patient/901");
|
||||
status = ourClient.execute(httpGet);
|
||||
response = extractResponseAndClose(status);
|
||||
assertEquals(403, status.getStatusLine().getStatusCode());
|
||||
assertEquals(ERR403, response);
|
||||
assertFalse(ourHitMethod);
|
||||
|
||||
ourHitMethod = false;
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Observation?_id=901");
|
||||
status = ourClient.execute(httpGet);
|
||||
response = extractResponseAndClose(status);
|
||||
assertEquals(403, status.getStatusLine().getStatusCode());
|
||||
assertEquals(ERR403, response);
|
||||
assertFalse(ourHitMethod);
|
||||
}
|
||||
|
||||
|
@ -3560,7 +3574,7 @@ public class AuthorizationInterceptorDstu3Test {
|
|||
}
|
||||
|
||||
@Search()
|
||||
public List<Resource> search(@OptionalParam(name = "_id") IdType theIdParam) {
|
||||
public List<Resource> search(@OptionalParam(name = "_id") TokenAndListParam theIdParam) {
|
||||
ourHitMethod = true;
|
||||
return ourReturn;
|
||||
}
|
||||
|
|
|
@ -299,6 +299,10 @@
|
|||
A wrapper script for Maven has been added, enabling new users to use Maven without having
|
||||
to install it beforehand. Thanks to Ari Ruotsalainen for the Pull Request!
|
||||
</action>
|
||||
<action type="add">
|
||||
AuthorizationInterceptor can now allow a user to perform a search that is scoped to a particular
|
||||
resource (e.g. Patient?_id=123) if the user has read access for that specific instance.
|
||||
</action>
|
||||
</release>
|
||||
<release version="3.6.0" date="2018-11-12" description="Food">
|
||||
<action type="add">
|
||||
|
|
Loading…
Reference in New Issue