Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
13243956f7
|
@ -113,6 +113,7 @@ public class LoincHandler implements IRecordHandler {
|
||||||
ourLog.warn("Unable to find part code with TYPE[{}] and NAME[{}]", key.getPartType(), key.getPartName());
|
ourLog.warn("Unable to find part code with TYPE[{}] and NAME[{}]", key.getPartType(), key.getPartName());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case DECIMAL:
|
||||||
case CODE:
|
case CODE:
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
case BOOLEAN:
|
case BOOLEAN:
|
||||||
|
|
|
@ -87,8 +87,8 @@ public class FhirTesterConfig {
|
||||||
.addServer()
|
.addServer()
|
||||||
.withId("spark2")
|
.withId("spark2")
|
||||||
.withFhirVersion(FhirVersionEnum.DSTU2)
|
.withFhirVersion(FhirVersionEnum.DSTU2)
|
||||||
.withBaseUrl("http://spark-dstu2.furore.com/fhir")
|
.withBaseUrl("http://vonk.furore.com/")
|
||||||
.withName("Spark - Furore (DSTU2 FHIR)");
|
.withName("Vonk - Furore (STU3 FHIR)");
|
||||||
|
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,24 +34,24 @@ public class ResourceBinding {
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceBinding.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceBinding.class);
|
||||||
|
|
||||||
private String resourceName;
|
private String resourceName;
|
||||||
private List<BaseMethodBinding<?>> methods = new ArrayList<BaseMethodBinding<?>>();
|
private List<BaseMethodBinding<?>> myMethodBindings = new ArrayList<>();
|
||||||
|
|
||||||
public ResourceBinding() {
|
public ResourceBinding() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResourceBinding(String resourceName, List<BaseMethodBinding<?>> methods) {
|
public ResourceBinding(String resourceName, List<BaseMethodBinding<?>> methods) {
|
||||||
this.resourceName = resourceName;
|
this.resourceName = resourceName;
|
||||||
this.methods = methods;
|
this.myMethodBindings = methods;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BaseMethodBinding<?> getMethod(RequestDetails theRequest) {
|
public BaseMethodBinding<?> getMethod(RequestDetails theRequest) {
|
||||||
if (null == methods) {
|
if (null == myMethodBindings) {
|
||||||
ourLog.warn("No methods exist for resource: {}", resourceName);
|
ourLog.warn("No methods exist for resource: {}", resourceName);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ourLog.debug("Looking for a handler for {}", theRequest);
|
ourLog.debug("Looking for a handler for {}", theRequest);
|
||||||
for (BaseMethodBinding<?> rm : methods) {
|
for (BaseMethodBinding<?> rm : myMethodBindings) {
|
||||||
if (rm.incomingServerRequestMatchesMethod(theRequest)) {
|
if (rm.incomingServerRequestMatchesMethod(theRequest)) {
|
||||||
ourLog.debug("Handler {} matches", rm);
|
ourLog.debug("Handler {} matches", rm);
|
||||||
return rm;
|
return rm;
|
||||||
|
@ -70,15 +70,15 @@ public class ResourceBinding {
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<BaseMethodBinding<?>> getMethodBindings() {
|
public List<BaseMethodBinding<?>> getMethodBindings() {
|
||||||
return methods;
|
return myMethodBindings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMethods(List<BaseMethodBinding<?>> methods) {
|
public void setMethods(List<BaseMethodBinding<?>> methods) {
|
||||||
this.methods = methods;
|
this.myMethodBindings = methods;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addMethod(BaseMethodBinding<?> method) {
|
public void addMethod(BaseMethodBinding<?> method) {
|
||||||
this.methods.add(method);
|
this.myMethodBindings.add(method);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -28,6 +28,8 @@ import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
|
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||||
import org.hl7.fhir.instance.model.api.IBase;
|
import org.hl7.fhir.instance.model.api.IBase;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
|
||||||
|
@ -220,6 +222,30 @@ public class OperationMethodBinding extends BaseResourceReturningMethodBinding {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RestOperationTypeEnum getRestOperationType(RequestDetails theRequestDetails) {
|
||||||
|
RestOperationTypeEnum retVal = super.getRestOperationType(theRequestDetails);
|
||||||
|
|
||||||
|
if (retVal == RestOperationTypeEnum.EXTENDED_OPERATION_INSTANCE) {
|
||||||
|
if (theRequestDetails.getId() == null) {
|
||||||
|
retVal = RestOperationTypeEnum.EXTENDED_OPERATION_TYPE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
|
||||||
|
.append("name", myName)
|
||||||
|
.append("methodName", getMethod().getDeclaringClass().getSimpleName() + "." + getMethod().getName())
|
||||||
|
.append("serverLevel", myCanOperateAtServerLevel)
|
||||||
|
.append("typeLevel", myCanOperateAtTypeLevel)
|
||||||
|
.append("instanceLevel", myCanOperateAtInstanceLevel)
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object invokeServer(IRestfulServer<?> theServer, RequestDetails theRequest) throws BaseServerResponseException, IOException {
|
public Object invokeServer(IRestfulServer<?> theServer, RequestDetails theRequest) throws BaseServerResponseException, IOException {
|
||||||
if (theRequest.getRequestType() == RequestTypeEnum.POST) {
|
if (theRequest.getRequestType() == RequestTypeEnum.POST) {
|
||||||
|
|
|
@ -366,9 +366,15 @@ public class StructureMapUtilities {
|
||||||
private static void renderGroup(StringBuilder b, StructureMapGroupComponent g) {
|
private static void renderGroup(StringBuilder b, StructureMapGroupComponent g) {
|
||||||
b.append("group ");
|
b.append("group ");
|
||||||
switch (g.getTypeMode()) {
|
switch (g.getTypeMode()) {
|
||||||
case TYPES: b.append("for types");
|
case TYPES:
|
||||||
case TYPEANDTYPES: b.append("for type+types ");
|
b.append("for types");
|
||||||
default: // NONE, NULL
|
break;
|
||||||
|
case TYPEANDTYPES:
|
||||||
|
b.append("for type+types ");
|
||||||
|
break;
|
||||||
|
case NONE:
|
||||||
|
case NULL:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
b.append("for types ");
|
b.append("for types ");
|
||||||
b.append(g.getName());
|
b.append(g.getName());
|
||||||
|
|
|
@ -6,13 +6,7 @@ import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.apache.commons.codec.Charsets;
|
import org.apache.commons.codec.Charsets;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
@ -250,7 +244,7 @@ public abstract class BaseWorkerContext implements IWorkerContext {
|
||||||
return laterVersion(newParts[i], oldParts[i]);
|
return laterVersion(newParts[i], oldParts[i]);
|
||||||
}
|
}
|
||||||
// This should never happen
|
// This should never happen
|
||||||
throw new Error("Delimited versions have exact match for delimiter '"+delimiter+"' : "+newParts+" vs "+oldParts);
|
throw new Error("Delimited versions have exact match for delimiter '"+delimiter+"' : "+ Arrays.asList(newParts)+" vs "+Arrays.asList(oldParts));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected <T extends MetadataResource> void seeMetadataResource(T r, Map<String, T> map, boolean addId) throws FHIRException {
|
protected <T extends MetadataResource> void seeMetadataResource(T r, Map<String, T> map, boolean addId) throws FHIRException {
|
||||||
|
@ -1045,6 +1039,8 @@ public abstract class BaseWorkerContext implements IWorkerContext {
|
||||||
return (T) maps.get(uri);
|
return (T) maps.get(uri);
|
||||||
if (transforms.containsKey(uri))
|
if (transforms.containsKey(uri))
|
||||||
return (T) transforms.get(uri);
|
return (T) transforms.get(uri);
|
||||||
|
if (questionnaires.containsKey(uri))
|
||||||
|
return (T) questionnaires.get(uri);
|
||||||
return null;
|
return null;
|
||||||
} else if (class_ == StructureDefinition.class) {
|
} else if (class_ == StructureDefinition.class) {
|
||||||
return (T) structures.get(uri);
|
return (T) structures.get(uri);
|
||||||
|
@ -1052,6 +1048,8 @@ public abstract class BaseWorkerContext implements IWorkerContext {
|
||||||
return (T) valueSets.get(uri);
|
return (T) valueSets.get(uri);
|
||||||
} else if (class_ == CodeSystem.class) {
|
} else if (class_ == CodeSystem.class) {
|
||||||
return (T) codeSystems.get(uri);
|
return (T) codeSystems.get(uri);
|
||||||
|
} else if (class_ == ConceptMap.class) {
|
||||||
|
return (T) maps.get(uri);
|
||||||
} else if (class_ == OperationDefinition.class) {
|
} else if (class_ == OperationDefinition.class) {
|
||||||
OperationDefinition od = operations.get(uri);
|
OperationDefinition od = operations.get(uri);
|
||||||
return (T) od;
|
return (T) od;
|
||||||
|
@ -1069,7 +1067,7 @@ public abstract class BaseWorkerContext implements IWorkerContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (class_ == Questionnaire.class)
|
if (class_ == Questionnaire.class)
|
||||||
return null;
|
return (T) questionnaires.get(uri);
|
||||||
if (class_ == null) {
|
if (class_ == null) {
|
||||||
if (uri.matches(Constants.URI_REGEX) && !uri.contains("ValueSet"))
|
if (uri.matches(Constants.URI_REGEX) && !uri.contains("ValueSet"))
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
package org.hl7.fhir.r4.utils;
|
package org.hl7.fhir.r4.utils;
|
||||||
|
|
||||||
//import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
//import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||||
|
|
||||||
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||||
import ca.uhn.fhir.util.ElementUtil;
|
import ca.uhn.fhir.util.ElementUtil;
|
||||||
|
|
||||||
import org.apache.commons.lang3.NotImplementedException;
|
import org.apache.commons.lang3.NotImplementedException;
|
||||||
|
import org.apache.http.protocol.ExecutionContext;
|
||||||
import org.fhir.ucum.Decimal;
|
import org.fhir.ucum.Decimal;
|
||||||
import org.fhir.ucum.Pair;
|
import org.fhir.ucum.Pair;
|
||||||
import org.fhir.ucum.UcumException;
|
import org.fhir.ucum.UcumException;
|
||||||
|
@ -24,8 +25,13 @@ import org.hl7.fhir.r4.utils.FHIRPathEngine.IEvaluationContext.FunctionDetails;
|
||||||
import org.hl7.fhir.utilities.Utilities;
|
import org.hl7.fhir.utilities.Utilities;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.StringUtils.length;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Grahame Grieve
|
* @author Grahame Grieve
|
||||||
|
@ -731,7 +737,7 @@ public class FHIRPathEngine {
|
||||||
String s = lexer.take();
|
String s = lexer.take();
|
||||||
if (s.equals("year") || s.equals("years"))
|
if (s.equals("year") || s.equals("years"))
|
||||||
ucum = "a";
|
ucum = "a";
|
||||||
else if (s.equals("month") || s.equals("month"))
|
else if (s.equals("month") || s.equals("months"))
|
||||||
ucum = "mo";
|
ucum = "mo";
|
||||||
else if (s.equals("week") || s.equals("weeks"))
|
else if (s.equals("week") || s.equals("weeks"))
|
||||||
ucum = "wk";
|
ucum = "wk";
|
||||||
|
@ -2072,8 +2078,9 @@ public class FHIRPathEngine {
|
||||||
result.add(item);
|
result.add(item);
|
||||||
} else
|
} else
|
||||||
getChildrenByName(item, exp.getName(), result);
|
getChildrenByName(item, exp.getName(), result);
|
||||||
// todo: GG 1st April 201 - why do this?
|
|
||||||
if (result.size() == 0 && atEntry && context.appInfo != null) {
|
if (result.size() == 0 && atEntry && context.appInfo != null) {
|
||||||
|
// well, we didn't get a match on the name - we'll see if the name matches a constant known by the context.
|
||||||
|
// (if the name does match, and the user wants to get the constant value, they'll have to try harder...
|
||||||
Base temp = hostServices.resolveConstant(context.appInfo, exp.getName());
|
Base temp = hostServices.resolveConstant(context.appInfo, exp.getName());
|
||||||
if (temp != null) {
|
if (temp != null) {
|
||||||
result.add(temp);
|
result.add(temp);
|
||||||
|
@ -3280,7 +3287,7 @@ public class FHIRPathEngine {
|
||||||
return Quantity.fromUcum(v, s.substring(1, s.length()-1));
|
return Quantity.fromUcum(v, s.substring(1, s.length()-1));
|
||||||
if (s.equals("year") || s.equals("years"))
|
if (s.equals("year") || s.equals("years"))
|
||||||
return Quantity.fromUcum(v, "a");
|
return Quantity.fromUcum(v, "a");
|
||||||
else if (s.equals("month") || s.equals("month"))
|
else if (s.equals("month") || s.equals("months"))
|
||||||
return Quantity.fromUcum(v, "mo");
|
return Quantity.fromUcum(v, "mo");
|
||||||
else if (s.equals("week") || s.equals("weeks"))
|
else if (s.equals("week") || s.equals("weeks"))
|
||||||
return Quantity.fromUcum(v, "wk");
|
return Quantity.fromUcum(v, "wk");
|
||||||
|
|
|
@ -97,6 +97,13 @@ public class AuthorizationInterceptorR4Test {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Organization createOrganization(int theIndex) {
|
||||||
|
Organization retVal = new Organization();
|
||||||
|
retVal.setId("" + theIndex);
|
||||||
|
retVal.setName("Org " + theIndex);
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
private Resource createPatient(Integer theId) {
|
private Resource createPatient(Integer theId) {
|
||||||
Patient retVal = new Patient();
|
Patient retVal = new Patient();
|
||||||
if (theId != null) {
|
if (theId != null) {
|
||||||
|
@ -820,6 +827,118 @@ public class AuthorizationInterceptorR4Test {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOperationAppliesAtAnyLevel() throws Exception {
|
||||||
|
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
||||||
|
@Override
|
||||||
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
|
return new RuleBuilder()
|
||||||
|
.allow("RULE 1").operation().named("opName").atAnyLevel().andThen()
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
HttpGet httpGet;
|
||||||
|
HttpResponse status;
|
||||||
|
String response;
|
||||||
|
|
||||||
|
// Server
|
||||||
|
ourHitMethod = false;
|
||||||
|
ourReturn = Collections.singletonList(createObservation(10, "Patient/2"));
|
||||||
|
httpGet = new HttpGet("http://localhost:" + ourPort + "/$opName");
|
||||||
|
status = ourClient.execute(httpGet);
|
||||||
|
response = extractResponseAndClose(status);
|
||||||
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
assertTrue(ourHitMethod);
|
||||||
|
|
||||||
|
// Type
|
||||||
|
ourHitMethod = false;
|
||||||
|
ourReturn = Collections.singletonList(createPatient(2));
|
||||||
|
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$opName");
|
||||||
|
status = ourClient.execute(httpGet);
|
||||||
|
response = extractResponseAndClose(status);
|
||||||
|
ourLog.info(response);
|
||||||
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
assertTrue(ourHitMethod);
|
||||||
|
|
||||||
|
// Instance
|
||||||
|
ourHitMethod = false;
|
||||||
|
ourReturn = Collections.singletonList(createPatient(2));
|
||||||
|
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1/$opName");
|
||||||
|
status = ourClient.execute(httpGet);
|
||||||
|
response = extractResponseAndClose(status);
|
||||||
|
ourLog.info(response);
|
||||||
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
assertTrue(ourHitMethod);
|
||||||
|
|
||||||
|
// Instance Version
|
||||||
|
ourHitMethod = false;
|
||||||
|
ourReturn = Collections.singletonList(createPatient(2));
|
||||||
|
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1/_history/2/$opName");
|
||||||
|
status = ourClient.execute(httpGet);
|
||||||
|
response = extractResponseAndClose(status);
|
||||||
|
ourLog.info(response);
|
||||||
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
assertTrue(ourHitMethod);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOperationAppliesAtAnyLevelWrongOpName() throws Exception {
|
||||||
|
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
||||||
|
@Override
|
||||||
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
|
return new RuleBuilder()
|
||||||
|
.allow("RULE 1").operation().named("opNameBadOp").atAnyLevel().andThen()
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
HttpGet httpGet;
|
||||||
|
HttpResponse status;
|
||||||
|
String response;
|
||||||
|
|
||||||
|
// Server
|
||||||
|
ourHitMethod = false;
|
||||||
|
ourReturn = Collections.singletonList(createObservation(10, "Patient/2"));
|
||||||
|
httpGet = new HttpGet("http://localhost:" + ourPort + "/$opName");
|
||||||
|
status = ourClient.execute(httpGet);
|
||||||
|
response = extractResponseAndClose(status);
|
||||||
|
assertEquals(403, status.getStatusLine().getStatusCode());
|
||||||
|
assertFalse(ourHitMethod);
|
||||||
|
|
||||||
|
// Type
|
||||||
|
ourHitMethod = false;
|
||||||
|
ourReturn = Collections.singletonList(createPatient(2));
|
||||||
|
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$opName");
|
||||||
|
status = ourClient.execute(httpGet);
|
||||||
|
response = extractResponseAndClose(status);
|
||||||
|
ourLog.info(response);
|
||||||
|
assertEquals(403, status.getStatusLine().getStatusCode());
|
||||||
|
assertFalse(ourHitMethod);
|
||||||
|
|
||||||
|
// Instance
|
||||||
|
ourHitMethod = false;
|
||||||
|
ourReturn = Collections.singletonList(createPatient(2));
|
||||||
|
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1/$opName");
|
||||||
|
status = ourClient.execute(httpGet);
|
||||||
|
response = extractResponseAndClose(status);
|
||||||
|
ourLog.info(response);
|
||||||
|
assertEquals(403, status.getStatusLine().getStatusCode());
|
||||||
|
assertFalse(ourHitMethod);
|
||||||
|
|
||||||
|
// Instance Version
|
||||||
|
ourHitMethod = false;
|
||||||
|
ourReturn = Collections.singletonList(createPatient(2));
|
||||||
|
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1/_history/2/$opName");
|
||||||
|
status = ourClient.execute(httpGet);
|
||||||
|
response = extractResponseAndClose(status);
|
||||||
|
ourLog.info(response);
|
||||||
|
assertEquals(403, status.getStatusLine().getStatusCode());
|
||||||
|
assertFalse(ourHitMethod);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOperationByInstanceOfTypeAllowed() throws Exception {
|
public void testOperationByInstanceOfTypeAllowed() throws Exception {
|
||||||
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
||||||
|
@ -1158,119 +1277,6 @@ public class AuthorizationInterceptorR4Test {
|
||||||
assertFalse(ourHitMethod);
|
assertFalse(ourHitMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testOperationAppliesAtAnyLevel() throws Exception {
|
|
||||||
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
|
||||||
@Override
|
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
|
||||||
return new RuleBuilder()
|
|
||||||
.allow("RULE 1").operation().named("opName").atAnyLevel().andThen()
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
HttpGet httpGet;
|
|
||||||
HttpResponse status;
|
|
||||||
String response;
|
|
||||||
|
|
||||||
// Server
|
|
||||||
ourHitMethod = false;
|
|
||||||
ourReturn = Collections.singletonList(createObservation(10, "Patient/2"));
|
|
||||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/$opName");
|
|
||||||
status = ourClient.execute(httpGet);
|
|
||||||
response = extractResponseAndClose(status);
|
|
||||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
|
||||||
assertTrue(ourHitMethod);
|
|
||||||
|
|
||||||
// Type
|
|
||||||
ourHitMethod = false;
|
|
||||||
ourReturn = Collections.singletonList(createPatient(2));
|
|
||||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$opName");
|
|
||||||
status = ourClient.execute(httpGet);
|
|
||||||
response = extractResponseAndClose(status);
|
|
||||||
ourLog.info(response);
|
|
||||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
|
||||||
assertTrue(ourHitMethod);
|
|
||||||
|
|
||||||
// Instance
|
|
||||||
ourHitMethod = false;
|
|
||||||
ourReturn = Collections.singletonList(createPatient(2));
|
|
||||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1/$opName");
|
|
||||||
status = ourClient.execute(httpGet);
|
|
||||||
response = extractResponseAndClose(status);
|
|
||||||
ourLog.info(response);
|
|
||||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
|
||||||
assertTrue(ourHitMethod);
|
|
||||||
|
|
||||||
// Instance Version
|
|
||||||
ourHitMethod = false;
|
|
||||||
ourReturn = Collections.singletonList(createPatient(2));
|
|
||||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1/_history/2/$opName");
|
|
||||||
status = ourClient.execute(httpGet);
|
|
||||||
response = extractResponseAndClose(status);
|
|
||||||
ourLog.info(response);
|
|
||||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
|
||||||
assertTrue(ourHitMethod);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testOperationAppliesAtAnyLevelWrongOpName() throws Exception {
|
|
||||||
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
|
||||||
@Override
|
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
|
||||||
return new RuleBuilder()
|
|
||||||
.allow("RULE 1").operation().named("opNameBadOp").atAnyLevel().andThen()
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
HttpGet httpGet;
|
|
||||||
HttpResponse status;
|
|
||||||
String response;
|
|
||||||
|
|
||||||
// Server
|
|
||||||
ourHitMethod = false;
|
|
||||||
ourReturn = Collections.singletonList(createObservation(10, "Patient/2"));
|
|
||||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/$opName");
|
|
||||||
status = ourClient.execute(httpGet);
|
|
||||||
response = extractResponseAndClose(status);
|
|
||||||
assertEquals(403, status.getStatusLine().getStatusCode());
|
|
||||||
assertFalse(ourHitMethod);
|
|
||||||
|
|
||||||
// Type
|
|
||||||
ourHitMethod = false;
|
|
||||||
ourReturn = Collections.singletonList(createPatient(2));
|
|
||||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$opName");
|
|
||||||
status = ourClient.execute(httpGet);
|
|
||||||
response = extractResponseAndClose(status);
|
|
||||||
ourLog.info(response);
|
|
||||||
assertEquals(403, status.getStatusLine().getStatusCode());
|
|
||||||
assertFalse(ourHitMethod);
|
|
||||||
|
|
||||||
// Instance
|
|
||||||
ourHitMethod = false;
|
|
||||||
ourReturn = Collections.singletonList(createPatient(2));
|
|
||||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1/$opName");
|
|
||||||
status = ourClient.execute(httpGet);
|
|
||||||
response = extractResponseAndClose(status);
|
|
||||||
ourLog.info(response);
|
|
||||||
assertEquals(403, status.getStatusLine().getStatusCode());
|
|
||||||
assertFalse(ourHitMethod);
|
|
||||||
|
|
||||||
// Instance Version
|
|
||||||
ourHitMethod = false;
|
|
||||||
ourReturn = Collections.singletonList(createPatient(2));
|
|
||||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1/_history/2/$opName");
|
|
||||||
status = ourClient.execute(httpGet);
|
|
||||||
response = extractResponseAndClose(status);
|
|
||||||
ourLog.info(response);
|
|
||||||
assertEquals(403, status.getStatusLine().getStatusCode());
|
|
||||||
assertFalse(ourHitMethod);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOperationTypeLevel() throws Exception {
|
public void testOperationTypeLevel() throws Exception {
|
||||||
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
||||||
|
@ -1408,6 +1414,64 @@ public class AuthorizationInterceptorR4Test {
|
||||||
assertFalse(ourHitMethod);
|
assertFalse(ourHitMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOperationTypeLevelWithOperationMethodHavingOptionalIdParam() throws Exception {
|
||||||
|
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
||||||
|
@Override
|
||||||
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
|
return new RuleBuilder()
|
||||||
|
.allow("RULE 1").operation().named("opName").onType(Organization.class).andThen()
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
HttpGet httpGet;
|
||||||
|
HttpResponse status;
|
||||||
|
String response;
|
||||||
|
|
||||||
|
// Server
|
||||||
|
ourHitMethod = false;
|
||||||
|
ourReturn = Collections.singletonList(createObservation(10, "Organization/2"));
|
||||||
|
httpGet = new HttpGet("http://localhost:" + ourPort + "/$opName");
|
||||||
|
status = ourClient.execute(httpGet);
|
||||||
|
response = extractResponseAndClose(status);
|
||||||
|
assertThat(response, containsString("Access denied by default policy"));
|
||||||
|
assertEquals(403, status.getStatusLine().getStatusCode());
|
||||||
|
assertFalse(ourHitMethod);
|
||||||
|
|
||||||
|
// Type
|
||||||
|
ourHitMethod = false;
|
||||||
|
ourReturn = Collections.singletonList(createOrganization(2));
|
||||||
|
httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization/$opName");
|
||||||
|
status = ourClient.execute(httpGet);
|
||||||
|
response = extractResponseAndClose(status);
|
||||||
|
ourLog.info(response);
|
||||||
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
assertTrue(ourHitMethod);
|
||||||
|
|
||||||
|
// Wrong type
|
||||||
|
ourHitMethod = false;
|
||||||
|
ourReturn = Collections.singletonList(createOrganization(2));
|
||||||
|
httpGet = new HttpGet("http://localhost:" + ourPort + "/Observation/1/$opName");
|
||||||
|
status = ourClient.execute(httpGet);
|
||||||
|
response = extractResponseAndClose(status);
|
||||||
|
ourLog.info(response);
|
||||||
|
assertThat(response, containsString("Access denied by default policy"));
|
||||||
|
assertEquals(403, status.getStatusLine().getStatusCode());
|
||||||
|
assertFalse(ourHitMethod);
|
||||||
|
|
||||||
|
// Instance
|
||||||
|
ourHitMethod = false;
|
||||||
|
ourReturn = Collections.singletonList(createOrganization(2));
|
||||||
|
httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization/1/$opName");
|
||||||
|
status = ourClient.execute(httpGet);
|
||||||
|
response = extractResponseAndClose(status);
|
||||||
|
ourLog.info(response);
|
||||||
|
assertThat(response, containsString("Access denied by default policy"));
|
||||||
|
assertEquals(403, status.getStatusLine().getStatusCode());
|
||||||
|
assertFalse(ourHitMethod);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOperationTypeLevelWithTenant() throws Exception {
|
public void testOperationTypeLevelWithTenant() throws Exception {
|
||||||
ourServlet.setTenantIdentificationStrategy(new UrlBaseTenantIdentificationStrategy());
|
ourServlet.setTenantIdentificationStrategy(new UrlBaseTenantIdentificationStrategy());
|
||||||
|
@ -2480,6 +2544,7 @@ public class AuthorizationInterceptorR4Test {
|
||||||
|
|
||||||
DummyPatientResourceProvider patProvider = new DummyPatientResourceProvider();
|
DummyPatientResourceProvider patProvider = new DummyPatientResourceProvider();
|
||||||
DummyObservationResourceProvider obsProv = new DummyObservationResourceProvider();
|
DummyObservationResourceProvider obsProv = new DummyObservationResourceProvider();
|
||||||
|
DummyOrganizationResourceProvider orgProv = new DummyOrganizationResourceProvider();
|
||||||
DummyEncounterResourceProvider encProv = new DummyEncounterResourceProvider();
|
DummyEncounterResourceProvider encProv = new DummyEncounterResourceProvider();
|
||||||
DummyCarePlanResourceProvider cpProv = new DummyCarePlanResourceProvider();
|
DummyCarePlanResourceProvider cpProv = new DummyCarePlanResourceProvider();
|
||||||
PlainProvider plainProvider = new PlainProvider();
|
PlainProvider plainProvider = new PlainProvider();
|
||||||
|
@ -2487,7 +2552,7 @@ public class AuthorizationInterceptorR4Test {
|
||||||
ServletHandler proxyHandler = new ServletHandler();
|
ServletHandler proxyHandler = new ServletHandler();
|
||||||
ourServlet = new RestfulServer(ourCtx);
|
ourServlet = new RestfulServer(ourCtx);
|
||||||
ourServlet.setFhirContext(ourCtx);
|
ourServlet.setFhirContext(ourCtx);
|
||||||
ourServlet.setResourceProviders(patProvider, obsProv, encProv, cpProv);
|
ourServlet.setResourceProviders(patProvider, obsProv, encProv, cpProv, orgProv);
|
||||||
ourServlet.setPlainProviders(plainProvider);
|
ourServlet.setPlainProviders(plainProvider);
|
||||||
ourServlet.setPagingProvider(new FifoMemoryPagingProvider(100));
|
ourServlet.setPagingProvider(new FifoMemoryPagingProvider(100));
|
||||||
ServletHolder servletHolder = new ServletHolder(ourServlet);
|
ServletHolder servletHolder = new ServletHolder(ourServlet);
|
||||||
|
@ -2541,6 +2606,25 @@ public class AuthorizationInterceptorR4Test {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class DummyOrganizationResourceProvider implements IResourceProvider {
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends IBaseResource> getResourceType() {
|
||||||
|
return Organization.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This should come before operation1
|
||||||
|
*/
|
||||||
|
@Operation(name = "opName", idempotent = true)
|
||||||
|
public Parameters operation0(@IdParam(optional = true) IdType theId) {
|
||||||
|
ourHitMethod = true;
|
||||||
|
return (Parameters) new Parameters().setId("1");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class DummyObservationResourceProvider implements IResourceProvider {
|
public static class DummyObservationResourceProvider implements IResourceProvider {
|
||||||
|
|
||||||
|
@ -2565,14 +2649,20 @@ public class AuthorizationInterceptorR4Test {
|
||||||
return Observation.class;
|
return Observation.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This should come before operation1
|
||||||
|
*/
|
||||||
@Operation(name = "opName", idempotent = true)
|
@Operation(name = "opName", idempotent = true)
|
||||||
public Parameters operation() {
|
public Parameters operation0(@IdParam IdType theId) {
|
||||||
ourHitMethod = true;
|
ourHitMethod = true;
|
||||||
return (Parameters) new Parameters().setId("1");
|
return (Parameters) new Parameters().setId("1");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This should come after operation0
|
||||||
|
*/
|
||||||
@Operation(name = "opName", idempotent = true)
|
@Operation(name = "opName", idempotent = true)
|
||||||
public Parameters operation(@IdParam IdType theId) {
|
public Parameters operation1() {
|
||||||
ourHitMethod = true;
|
ourHitMethod = true;
|
||||||
return (Parameters) new Parameters().setId("1");
|
return (Parameters) new Parameters().setId("1");
|
||||||
}
|
}
|
||||||
|
@ -2670,13 +2760,17 @@ public class AuthorizationInterceptorR4Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operation(name = "opName", idempotent = true)
|
@Operation(name = "opName", idempotent = true)
|
||||||
public Parameters operation() {
|
public Parameters operation0(@IdParam IdType theId) {
|
||||||
ourHitMethod = true;
|
ourHitMethod = true;
|
||||||
return (Parameters) new Parameters().setId("1");
|
return (Parameters) new Parameters().setId("1");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* More generic method second to make sure that the
|
||||||
|
* other method takes precedence
|
||||||
|
*/
|
||||||
@Operation(name = "opName", idempotent = true)
|
@Operation(name = "opName", idempotent = true)
|
||||||
public Parameters operation(@IdParam IdType theId) {
|
public Parameters operation1() {
|
||||||
ourHitMethod = true;
|
ourHitMethod = true;
|
||||||
return (Parameters) new Parameters().setId("1");
|
return (Parameters) new Parameters().setId("1");
|
||||||
}
|
}
|
||||||
|
|
27
pom.xml
27
pom.xml
|
@ -1538,19 +1538,20 @@
|
||||||
</goals>
|
</goals>
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
<configuration>
|
<configuration>
|
||||||
<rules>
|
<rules>
|
||||||
<requireMavenVersion>
|
<requireMavenVersion>
|
||||||
<version>3.5</version>
|
<version>3.3</version>
|
||||||
</requireMavenVersion>
|
</requireMavenVersion>
|
||||||
<requireJavaVersion>
|
<requireJavaVersion>
|
||||||
<version>[1.8,)</version>
|
<!--<version>[1.8,)</version>-->
|
||||||
<message>
|
<version>1.8</version>
|
||||||
The hapi-fhir Maven build requires JDK version 1.8 or higher.
|
<message>
|
||||||
</message>
|
The hapi-fhir Maven build requires JDK version 1.8.x.
|
||||||
</requireJavaVersion>
|
</message>
|
||||||
</rules>
|
</requireJavaVersion>
|
||||||
</configuration>
|
</rules>
|
||||||
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
|
|
@ -167,6 +167,11 @@
|
||||||
to occasionally consume two database connections, which could lead to deadlocks
|
to occasionally consume two database connections, which could lead to deadlocks
|
||||||
under heavy load. This has been fixed.
|
under heavy load. This has been fixed.
|
||||||
</action>
|
</action>
|
||||||
|
<action type="fix">
|
||||||
|
AuthorizationInterceptor sometimes incorrectly identified an operation
|
||||||
|
invocation at the type level as being at the instance level if the method
|
||||||
|
indicated that the IdParam parameter was optional. This has been fixed.
|
||||||
|
</action>
|
||||||
</release>
|
</release>
|
||||||
<release version="3.3.0" date="2018-03-29">
|
<release version="3.3.0" date="2018-03-29">
|
||||||
<action type="add">
|
<action type="add">
|
||||||
|
|
Loading…
Reference in New Issue