Add subscription narrowing interceptor and refactor RuleBuilder to be a

bit cleaner
This commit is contained in:
James Agnew 2019-01-12 14:23:26 -06:00
parent fc09ed6966
commit 93bf2788ec
10 changed files with 326 additions and 120 deletions

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.rest.server.interceptor.auth;
/*-
* #%L
* HAPI FHIR - Server Framework
* %%
* Copyright (C) 2014 - 2019 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%
*/
import ca.uhn.fhir.rest.api.server.RequestDetails;
import org.apache.commons.lang3.Validate;
@ -11,15 +31,15 @@ import java.util.List;
*/
public class AuthorizedList {
private List<String> myCompartments;
private List<String> myResources;
private List<String> myAllowedCompartments;
private List<String> myAllowedInstances;
List<String> getCompartments() {
return myCompartments;
List<String> getAllowedCompartments() {
return myAllowedCompartments;
}
List<String> getResources() {
return myResources;
List<String> getAllowedInstances() {
return myAllowedInstances;
}
/**
@ -30,10 +50,10 @@ public class AuthorizedList {
*/
public AuthorizedList addCompartment(String theCompartment) {
Validate.notNull(theCompartment, "theCompartment must not be null");
if (myCompartments == null) {
myCompartments = new ArrayList<>();
if (myAllowedCompartments == null) {
myAllowedCompartments = new ArrayList<>();
}
myCompartments.add(theCompartment);
myAllowedCompartments.add(theCompartment);
return this;
}
@ -60,10 +80,10 @@ public class AuthorizedList {
*/
public AuthorizedList addResource(String theResource) {
Validate.notNull(theResource, "theResource must not be null");
if (myResources == null) {
myResources = new ArrayList<>();
if (myAllowedInstances == null) {
myAllowedInstances = new ArrayList<>();
}
myResources.add(theResource);
myAllowedInstances.add(theResource);
return this;
}

View File

@ -2,6 +2,8 @@ package ca.uhn.fhir.rest.server.interceptor.auth;
import org.hl7.fhir.instance.model.api.IIdType;
import java.util.Collection;
/*
* #%L
* HAPI FHIR - Server Framework
@ -58,4 +60,5 @@ public interface IAuthRuleBuilderRuleOp extends IAuthRuleBuilderAppliesTo<IAuthR
*/
IAuthRuleFinished instance(IIdType theId);
IAuthRuleFinished instances(Collection<IIdType> theInstances);
}

View File

@ -172,7 +172,6 @@ public class RuleBuilder implements IAuthRuleBuilder {
private PolicyEnum myRuleMode;
private String myRuleName;
private RuleOpEnum myRuleOp;
RuleBuilderRule(PolicyEnum theRuleMode, String theRuleName) {
myRuleMode = theRuleMode;
@ -186,8 +185,7 @@ public class RuleBuilder implements IAuthRuleBuilder {
@Override
public IAuthRuleBuilderRuleOp delete() {
myRuleOp = RuleOpEnum.DELETE;
return new RuleBuilderRuleOp();
return new RuleBuilderRuleOp(RuleOpEnum.DELETE);
}
@Override
@ -211,14 +209,12 @@ public class RuleBuilder implements IAuthRuleBuilder {
@Override
public IAuthRuleBuilderPatch patch() {
myRuleOp = RuleOpEnum.PATCH;
return new PatchBuilder();
}
@Override
public IAuthRuleBuilderRuleOp read() {
myRuleOp = RuleOpEnum.READ;
return new RuleBuilderRuleOp();
return new RuleBuilderRuleOp(RuleOpEnum.READ);
}
@Override
@ -233,8 +229,7 @@ public class RuleBuilder implements IAuthRuleBuilder {
@Override
public IAuthRuleBuilderRuleOp write() {
myRuleOp = RuleOpEnum.WRITE;
return new RuleBuilderRuleOp();
return new RuleBuilderRuleOp(RuleOpEnum.WRITE);
}
@Override
@ -245,7 +240,6 @@ public class RuleBuilder implements IAuthRuleBuilder {
private class RuleBuilderRuleConditional implements IAuthRuleBuilderRuleConditional {
private AppliesTypeEnum myAppliesTo;
private Set<?> myAppliesToTypes;
private RestOperationTypeEnum myOperationType;
@ -291,13 +285,15 @@ public class RuleBuilder implements IAuthRuleBuilder {
private class RuleBuilderRuleOp implements IAuthRuleBuilderRuleOp {
private AppliesTypeEnum myAppliesTo;
private Set<?> myAppliesToTypes;
private final RuleOpEnum myRuleOp;
public RuleBuilderRuleOp(RuleOpEnum theRuleOp) {
myRuleOp = theRuleOp;
}
@Override
public IAuthRuleBuilderRuleOpClassifier allResources() {
myAppliesTo = AppliesTypeEnum.ALL_RESOURCES;
return new RuleBuilderRuleOpClassifier();
return new RuleBuilderRuleOpClassifier(AppliesTypeEnum.ALL_RESOURCES, null);
}
@Override
@ -312,15 +308,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");
return new RuleBuilderRuleOpClassifier(Collections.singletonList(theId)).finished();
List<IIdType> instances = Collections.singletonList(theId);
return instances(instances);
}
@Override
public IAuthRuleFinished 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();
}
@Override
public IAuthRuleBuilderRuleOpClassifier resourcesOfType(Class<? extends IBaseResource> theType) {
Validate.notNull(theType, "theType must not be null");
myAppliesTo = AppliesTypeEnum.TYPES;
myAppliesToTypes = Collections.singleton(theType);
return new RuleBuilderRuleOpClassifier();
return new RuleBuilderRuleOpClassifier(AppliesTypeEnum.TYPES, Collections.singleton(theType));
}
private class RuleBuilderRuleOpClassifier implements IAuthRuleBuilderRuleOpClassifier {
@ -328,21 +331,26 @@ public class RuleBuilder implements IAuthRuleBuilder {
private ClassifierTypeEnum myClassifierType;
private String myInCompartmentName;
private Collection<? extends IIdType> myInCompartmentOwners;
private List<IIdType> myAppliesToInstances;
private Collection<IIdType> myAppliesToInstances;
private final AppliesTypeEnum myAppliesTo;
private final Set<?> myAppliesToTypes;
/**
* Constructor
*/
RuleBuilderRuleOpClassifier() {
RuleBuilderRuleOpClassifier(AppliesTypeEnum theAppliesTo, Set<Class<? extends IBaseResource>> theAppliesToTypes) {
super();
myAppliesTo = theAppliesTo;
myAppliesToTypes=theAppliesToTypes;
}
/**
* Constructor
*/
RuleBuilderRuleOpClassifier(List<IIdType> theAppliesToInstances) {
RuleBuilderRuleOpClassifier(Collection<IIdType> theAppliesToInstances) {
myAppliesToInstances = theAppliesToInstances;
myAppliesTo = AppliesTypeEnum.INSTANCES;
myAppliesToTypes = null;
}
private IAuthRuleBuilderRuleOpClassifierFinished finished() {
@ -554,6 +562,10 @@ public class RuleBuilder implements IAuthRuleBuilder {
private class PatchBuilder implements IAuthRuleBuilderPatch {
public PatchBuilder() {
super();
}
@Override
public IAuthRuleFinished allRequests() {
BaseRule rule = new RuleImplPatch(myRuleName)

View File

@ -20,10 +20,7 @@ import org.hl7.fhir.instance.model.api.IBaseBundle;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
@ -48,6 +45,7 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
* #L%
*/
@SuppressWarnings("EnumSwitchStatementWhichMissesCases")
class RuleImplOp extends BaseRule /* implements IAuthRule */ {
private AppliesTypeEnum myAppliesTo;
@ -57,7 +55,7 @@ class RuleImplOp extends BaseRule /* implements IAuthRule */ {
private ClassifierTypeEnum myClassifierType;
private RuleOpEnum myOp;
private TransactionAppliesToEnum myTransactionAppliesToOp;
private List<IIdType> myAppliesToInstances;
private Collection<IIdType> myAppliesToInstances;
/**
* Constructor
@ -77,7 +75,7 @@ class RuleImplOp extends BaseRule /* implements IAuthRule */ {
FhirContext ctx = theRequestDetails.getServer().getFhirContext();
IBaseResource appliesToResource;
IIdType appliesToResourceId = null;
Collection<IIdType> appliesToResourceId = null;
String appliesToResourceType = null;
Map<String, String[]> appliesToSearchParams = null;
switch (myOp) {
@ -90,7 +88,7 @@ class RuleImplOp extends BaseRule /* implements IAuthRule */ {
switch (theOperation) {
case READ:
case VREAD:
appliesToResourceId = theInputResourceId;
appliesToResourceId = Collections.singleton(theInputResourceId);
appliesToResourceType = theInputResourceId.getResourceType();
break;
case SEARCH_SYSTEM:
@ -105,6 +103,29 @@ class RuleImplOp extends BaseRule /* implements IAuthRule */ {
}
appliesToResourceType = theRequestDetails.getResourceName();
appliesToSearchParams = theRequestDetails.getParameters();
/*
* If this is a search with an "_id" parameter, we can treat this
* as a read for the given resource ID(s)
*/
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);
}
}
}
if (appliesToResourceId.isEmpty()) {
appliesToResourceId = null;
}
}
break;
case HISTORY_TYPE:
if (theFlags.contains(AuthorizationFlagsEnum.NO_NOT_PROACTIVELY_BLOCK_COMPARTMENT_READ_ACCESS)) {
@ -116,7 +137,7 @@ class RuleImplOp extends BaseRule /* implements IAuthRule */ {
if (theFlags.contains(AuthorizationFlagsEnum.NO_NOT_PROACTIVELY_BLOCK_COMPARTMENT_READ_ACCESS)) {
return new Verdict(PolicyEnum.ALLOW, this);
}
appliesToResourceId = theInputResourceId;
appliesToResourceId = Collections.singleton(theInputResourceId);
break;
case GET_PAGE:
return new Verdict(PolicyEnum.ALLOW, this);
@ -145,7 +166,7 @@ class RuleImplOp extends BaseRule /* implements IAuthRule */ {
}
appliesToResource = theOutputResource;
if (theOutputResource != null) {
appliesToResourceId = theOutputResource.getIdElement();
appliesToResourceId = Collections.singleton(theOutputResource.getIdElement());
}
break;
case WRITE:
@ -160,7 +181,9 @@ class RuleImplOp extends BaseRule /* implements IAuthRule */ {
case META_ADD:
case META_DELETE:
appliesToResource = theInputResource;
appliesToResourceId = theInputResourceId;
if (theInputResourceId != null) {
appliesToResourceId = Collections.singletonList(theInputResourceId);
}
break;
default:
return null;
@ -291,19 +314,29 @@ class RuleImplOp extends BaseRule /* implements IAuthRule */ {
switch (myAppliesTo) {
case INSTANCES:
if (appliesToResourceId != null) {
if (appliesToResourceId != null && appliesToResourceId.size() > 0) {
int haveMatches = 0;
for (IIdType requestAppliesToResource : appliesToResourceId) {
for (IIdType next : myAppliesToInstances) {
if (isNotBlank(next.getResourceType())) {
if (!next.getResourceType().equals(appliesToResourceId.getResourceType())) {
if (!next.getResourceType().equals(requestAppliesToResource.getResourceType())) {
continue;
}
}
if (!next.getIdPart().equals(appliesToResourceId.getIdPart())) {
if (!next.getIdPart().equals(requestAppliesToResource.getIdPart())) {
continue;
}
if (!applyTesters(theOperation, theRequestDetails, theInputResourceId, theInputResource, theOutputResource)) {
return null;
}
haveMatches++;
break;
}
}
if (haveMatches == appliesToResourceId.size()) {
return newVerdict();
}
}
@ -326,12 +359,16 @@ class RuleImplOp extends BaseRule /* implements IAuthRule */ {
}
}
}
if (appliesToResourceId != null && appliesToResourceId.hasResourceType()) {
Class<? extends IBaseResource> type = theRequestDetails.getServer().getFhirContext().getResourceDefinition(appliesToResourceId.getResourceType()).getImplementingClass();
if (appliesToResourceId != null) {
for (IIdType nextRequestAppliesToResourceId : appliesToResourceId) {
if (nextRequestAppliesToResourceId.hasResourceType()) {
Class<? extends IBaseResource> type = theRequestDetails.getServer().getFhirContext().getResourceDefinition(nextRequestAppliesToResourceId.getResourceType()).getImplementingClass();
if (myAppliesToTypes.contains(type) == false) {
return null;
}
}
}
}
if (appliesToResourceType != null) {
Class<? extends IBaseResource> type = theRequestDetails.getServer().getFhirContext().getResourceDefinition(appliesToResourceType).getImplementingClass();
if (myAppliesToTypes.contains(type)) {
@ -356,6 +393,16 @@ class RuleImplOp extends BaseRule /* implements IAuthRule */ {
case IN_COMPARTMENT:
FhirTerser t = ctx.newTerser();
boolean foundMatch = false;
if (appliesToResourceId != null && appliesToResourceId.size() > 0) {
boolean haveOwnersForAll = appliesToResourceId
.stream()
.allMatch(n -> myClassifierCompartmentOwners.contains(n.toUnqualifiedVersionless()));
if (haveOwnersForAll) {
foundMatch = true;
}
}
for (IIdType next : myClassifierCompartmentOwners) {
if (appliesToResource != null) {
if (t.isSourceInCompartmentForTarget(myClassifierCompartmentName, appliesToResource, next)) {
@ -363,12 +410,6 @@ class RuleImplOp extends BaseRule /* implements IAuthRule */ {
break;
}
}
if (appliesToResourceId != null && appliesToResourceId.hasResourceType() && appliesToResourceId.hasIdPart()) {
if (appliesToResourceId.toUnqualifiedVersionless().getValue().equals(next.toUnqualifiedVersionless().getValue())) {
foundMatch = true;
break;
}
}
/*
* If the client has permission to read compartment
@ -490,7 +531,7 @@ class RuleImplOp extends BaseRule /* implements IAuthRule */ {
myAppliesTo = theAppliesTo;
}
public void setAppliesToInstances(List<IIdType> theAppliesToInstances) {
public void setAppliesToInstances(Collection<IIdType> theAppliesToInstances) {
myAppliesToInstances = theAppliesToInstances;
}

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.rest.server.interceptor.auth;
/*-
* #%L
* HAPI FHIR - Server Framework
* %%
* Copyright (C) 2014 - 2019 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%
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.context.RuntimeSearchParam;
@ -51,9 +71,12 @@ public abstract class SearchNarrowingInterceptor extends InterceptorAdapter {
* </p>
*
* @param theRequestDetails The individual request currently being applied
* @return The list of allowed compartments and instances that should be used
* for search narrowing. If this method returns <code>null</code>, no narrowing will
* be performed
*/
protected AuthorizedList buildAuthorizedList(@SuppressWarnings("unused") RequestDetails theRequestDetails) {
return new AuthorizedList();
return null;
}
@ -71,16 +94,19 @@ public abstract class SearchNarrowingInterceptor extends InterceptorAdapter {
RuntimeResourceDefinition resDef = ctx.getResourceDefinition(theRequestDetails.getResourceName());
HashMap<String, List<String>> parameterToOrValues = new HashMap<>();
AuthorizedList authorizedList = buildAuthorizedList(theRequestDetails);
if (authorizedList == null) {
return true;
}
/*
* Create a map of search parameter values that need to be added to the
* given request
*/
Collection<String> compartments = authorizedList.getCompartments();
Collection<String> compartments = authorizedList.getAllowedCompartments();
if (compartments != null) {
processResourcesOrCompartments(theRequestDetails, resDef, parameterToOrValues, compartments, true);
}
Collection<String> resources = authorizedList.getResources();
Collection<String> resources = authorizedList.getAllowedInstances();
if (resources != null) {
processResourcesOrCompartments(theRequestDetails, resDef, parameterToOrValues, resources, false);
}
@ -147,7 +173,7 @@ public abstract class SearchNarrowingInterceptor extends InterceptorAdapter {
private void processResourcesOrCompartments(RequestDetails theRequestDetails, RuntimeResourceDefinition theResDef, HashMap<String, List<String>> theParameterToOrValues, Collection<String> theResourcesOrCompartments, boolean theAreCompartments) {
String lastCompartmentName = null;
String lastSearchParamName=null;
String lastSearchParamName = null;
for (String nextCompartment : theResourcesOrCompartments) {
Validate.isTrue(StringUtils.countMatches(nextCompartment, '/') == 1, "Invalid compartment name (must be in form \"ResourceType/xxx\": %s", nextCompartment);
String compartmentName = nextCompartment.substring(0, nextCompartment.indexOf('/'));

View File

@ -0,0 +1,14 @@
package ca.uhn.fhir.rest.server.interceptor.auth;
import org.junit.Test;
import static org.junit.Assert.*;
public class RuleBuilderTest {
@Test
public void testCollapseReadInstancesIntoSingleRule() {
}
}

View File

@ -9,6 +9,7 @@ import ca.uhn.fhir.rest.api.*;
import ca.uhn.fhir.rest.api.server.IRequestOperationCallback;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.param.ReferenceParam;
import ca.uhn.fhir.rest.param.TokenAndListParam;
import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider;
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.RestfulServer;
@ -629,7 +630,7 @@ public class AuthorizationInterceptorDstu3Test {
httpPost.setEntity(new StringEntity(ourCtx.newJsonParser().encodeResourceToString(bundle), ContentType.create(Constants.CT_FHIR_JSON_NEW, Charsets.UTF_8)));
status = ourClient.execute(httpPost);
responseString = extractResponseAndClose(status);
assertEquals(responseString,403, status.getStatusLine().getStatusCode());
assertEquals(responseString, 403, status.getStatusLine().getStatusCode());
assertTrue(ourHitMethod);
bundle.getEntry().clear();
@ -640,7 +641,7 @@ public class AuthorizationInterceptorDstu3Test {
httpPost.setEntity(new StringEntity(ourCtx.newJsonParser().encodeResourceToString(bundle), ContentType.create(Constants.CT_FHIR_JSON_NEW, Charsets.UTF_8)));
status = ourClient.execute(httpPost);
responseString = extractResponseAndClose(status);
assertEquals(responseString,200, status.getStatusLine().getStatusCode());
assertEquals(responseString, 200, status.getStatusLine().getStatusCode());
assertTrue(ourHitMethod);
ourHitMethod = false;
@ -652,7 +653,7 @@ public class AuthorizationInterceptorDstu3Test {
httpPost.setEntity(new StringEntity(ourCtx.newJsonParser().encodeResourceToString(bundle), ContentType.create(Constants.CT_FHIR_JSON_NEW, Charsets.UTF_8)));
status = ourClient.execute(httpPost);
responseString = extractResponseAndClose(status);
assertEquals(responseString,403, status.getStatusLine().getStatusCode());
assertEquals(responseString, 403, status.getStatusLine().getStatusCode());
assertTrue(ourHitMethod);
ourHitMethod = false;
@ -664,7 +665,7 @@ public class AuthorizationInterceptorDstu3Test {
httpPost.setEntity(new StringEntity(ourCtx.newJsonParser().encodeResourceToString(bundle), ContentType.create(Constants.CT_FHIR_JSON_NEW, Charsets.UTF_8)));
status = ourClient.execute(httpPost);
responseString = extractResponseAndClose(status);
assertEquals(responseString,200, status.getStatusLine().getStatusCode());
assertEquals(responseString, 200, status.getStatusLine().getStatusCode());
assertTrue(ourHitMethod);
}
@ -2499,6 +2500,73 @@ public class AuthorizationInterceptorDstu3Test {
}
@Test
public void testReadByInstanceAllowsTargetedSearch() throws Exception {
ourConditionalCreateId = "1";
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();
}
});
HttpResponse status;
String response;
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);
}
@Test
public void testReadPageRight() throws Exception {
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
@ -3205,45 +3273,6 @@ public class AuthorizationInterceptorDstu3Test {
assertTrue(ourHitMethod);
}
@AfterClass
public static void afterClassClearContext() throws Exception {
ourServer.stop();
TestUtil.clearAllStaticFieldsForUnitTest();
}
@BeforeClass
public static void beforeClass() throws Exception {
ourPort = PortUtil.findFreePort();
ourServer = new Server(ourPort);
DummyPatientResourceProvider patProvider = new DummyPatientResourceProvider();
DummyObservationResourceProvider obsProv = new DummyObservationResourceProvider();
DummyOrganizationResourceProvider orgProv = new DummyOrganizationResourceProvider();
DummyEncounterResourceProvider encProv = new DummyEncounterResourceProvider();
DummyCarePlanResourceProvider cpProv = new DummyCarePlanResourceProvider();
DummyDiagnosticReportResourceProvider drProv = new DummyDiagnosticReportResourceProvider();
DummyMessageHeaderResourceProvider mshProv = new DummyMessageHeaderResourceProvider();
PlainProvider plainProvider = new PlainProvider();
ServletHandler proxyHandler = new ServletHandler();
ourServlet = new RestfulServer(ourCtx);
ourServlet.setFhirContext(ourCtx);
ourServlet.setResourceProviders(patProvider, obsProv, encProv, cpProv, orgProv, drProv, mshProv);
ourServlet.setPlainProviders(plainProvider);
ourServlet.setPagingProvider(new FifoMemoryPagingProvider(100));
ServletHolder servletHolder = new ServletHolder(ourServlet);
proxyHandler.addServletWithMapping(servletHolder, "/*");
ourServer.setHandler(proxyHandler);
ourServer.start();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
HttpClientBuilder builder = HttpClientBuilder.create();
builder.setConnectionManager(connectionManager);
ourClient = builder.build();
}
public static class DummyCarePlanResourceProvider implements IResourceProvider {
@Override
@ -3314,7 +3343,7 @@ public class AuthorizationInterceptorDstu3Test {
}
@Operation(name = "process-message", idempotent = true)
public Parameters operation0(@OperationParam(name="content") Bundle theInput) {
public Parameters operation0(@OperationParam(name = "content") Bundle theInput) {
ourHitMethod = true;
return (Parameters) new Parameters().setId("1");
}
@ -3397,7 +3426,9 @@ public class AuthorizationInterceptorDstu3Test {
}
@Search()
public List<Resource> search(@OptionalParam(name = "subject") ReferenceParam theSubject) {
public List<Resource> search(
@OptionalParam(name = "_id") TokenAndListParam theIds,
@OptionalParam(name = "subject") ReferenceParam theSubject) {
ourHitMethod = true;
return ourReturn;
}
@ -3591,7 +3622,7 @@ public class AuthorizationInterceptorDstu3Test {
@Transaction()
public Bundle search(IRequestOperationCallback theRequestOperationCallback, @TransactionParam Bundle theInput) {
ourHitMethod = true;
if (ourDeleted != null){
if (ourDeleted != null) {
for (IBaseResource next : ourDeleted) {
theRequestOperationCallback.resourceDeleted(next);
}
@ -3601,6 +3632,45 @@ public class AuthorizationInterceptorDstu3Test {
}
@AfterClass
public static void afterClassClearContext() throws Exception {
ourServer.stop();
TestUtil.clearAllStaticFieldsForUnitTest();
}
@BeforeClass
public static void beforeClass() throws Exception {
ourPort = PortUtil.findFreePort();
ourServer = new Server(ourPort);
DummyPatientResourceProvider patProvider = new DummyPatientResourceProvider();
DummyObservationResourceProvider obsProv = new DummyObservationResourceProvider();
DummyOrganizationResourceProvider orgProv = new DummyOrganizationResourceProvider();
DummyEncounterResourceProvider encProv = new DummyEncounterResourceProvider();
DummyCarePlanResourceProvider cpProv = new DummyCarePlanResourceProvider();
DummyDiagnosticReportResourceProvider drProv = new DummyDiagnosticReportResourceProvider();
DummyMessageHeaderResourceProvider mshProv = new DummyMessageHeaderResourceProvider();
PlainProvider plainProvider = new PlainProvider();
ServletHandler proxyHandler = new ServletHandler();
ourServlet = new RestfulServer(ourCtx);
ourServlet.setFhirContext(ourCtx);
ourServlet.setResourceProviders(patProvider, obsProv, encProv, cpProv, orgProv, drProv, mshProv);
ourServlet.setPlainProviders(plainProvider);
ourServlet.setPagingProvider(new FifoMemoryPagingProvider(100));
ourServlet.setDefaultResponseEncoding(EncodingEnum.JSON);
ServletHolder servletHolder = new ServletHolder(ourServlet);
proxyHandler.addServletWithMapping(servletHolder, "/*");
ourServer.setHandler(proxyHandler);
ourServer.start();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
HttpClientBuilder builder = HttpClientBuilder.create();
builder.setConnectionManager(connectionManager);
ourClient = builder.build();
}
}

View File

@ -68,6 +68,24 @@ public class SearchNarrowingInterceptorTest {
ourNextCompartmentList = null;
}
@Test
public void testReturnNull() {
ourNextCompartmentList = null;
ourClient
.search()
.forResource("Patient")
.execute();
assertEquals("Patient.search", ourLastHitMethod);
assertNull(ourLastCodeParam);
assertNull(ourLastSubjectParam);
assertNull(ourLastPerformerParam);
assertNull(ourLastPatientParam);
assertNull(ourLastIdParam);
}
@Test
public void testNarrowObservationsByPatientContext_ClientRequestedNoParams() {
@ -259,7 +277,9 @@ public class SearchNarrowingInterceptorTest {
private static class MySearchNarrowingInterceptor extends SearchNarrowingInterceptor {
@Override
protected AuthorizedList buildAuthorizedList(RequestDetails theRequestDetails) {
Validate.notNull(ourNextCompartmentList);
if (ourNextCompartmentList == null) {
return null;
}
return ourNextCompartmentList;
}
}