AuthorizationInterceptor concurrency failure (#3528)
* Fix #3256 - AuthorizationInterceptor concurrency failure * Test fixes
This commit is contained in:
parent
c29bb462c5
commit
7dec2e334d
|
@ -217,6 +217,12 @@ public class RuntimeResourceDefinition extends BaseRuntimeElementCompositeDefini
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make the map of lists completely unmodifiable
|
||||||
|
for (String nextKey : new ArrayList<>(compartmentNameToSearchParams.keySet())) {
|
||||||
|
List<RuntimeSearchParam> nextList = compartmentNameToSearchParams.get(nextKey);
|
||||||
|
compartmentNameToSearchParams.put(nextKey, Collections.unmodifiableList(nextList));
|
||||||
|
}
|
||||||
myCompartmentNameToSearchParams = Collections.unmodifiableMap(compartmentNameToSearchParams);
|
myCompartmentNameToSearchParams = Collections.unmodifiableMap(compartmentNameToSearchParams);
|
||||||
|
|
||||||
Class<?> target = getImplementingClass();
|
Class<?> target = getImplementingClass();
|
||||||
|
|
|
@ -748,7 +748,7 @@ public class FhirTerser {
|
||||||
|
|
||||||
List<RuntimeSearchParam> params = sourceDef.getSearchParamsForCompartmentName(theCompartmentName);
|
List<RuntimeSearchParam> params = sourceDef.getSearchParamsForCompartmentName(theCompartmentName);
|
||||||
|
|
||||||
//If passed an additional set of searchparameter names, add them for comparison purposes.
|
// If passed an additional set of searchparameter names, add them for comparison purposes.
|
||||||
if (theAdditionalCompartmentParamNames != null) {
|
if (theAdditionalCompartmentParamNames != null) {
|
||||||
List<RuntimeSearchParam> additionalParams = theAdditionalCompartmentParamNames.stream().map(sourceDef::getSearchParam)
|
List<RuntimeSearchParam> additionalParams = theAdditionalCompartmentParamNames.stream().map(sourceDef::getSearchParam)
|
||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
|
@ -756,6 +756,9 @@ public class FhirTerser {
|
||||||
if (params == null || params.isEmpty()) {
|
if (params == null || params.isEmpty()) {
|
||||||
params = additionalParams;
|
params = additionalParams;
|
||||||
} else {
|
} else {
|
||||||
|
List<RuntimeSearchParam> existingParams = params;
|
||||||
|
params = new ArrayList<>(existingParams.size() + additionalParams.size());
|
||||||
|
params.addAll(existingParams);
|
||||||
params.addAll(additionalParams);
|
params.addAll(additionalParams);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,10 @@ public class UrlUtil {
|
||||||
private static final String URL_FORM_PARAMETER_OTHER_SAFE_CHARS = "-_.*";
|
private static final String URL_FORM_PARAMETER_OTHER_SAFE_CHARS = "-_.*";
|
||||||
private static final Escaper PARAMETER_ESCAPER = new PercentEscaper(URL_FORM_PARAMETER_OTHER_SAFE_CHARS, false);
|
private static final Escaper PARAMETER_ESCAPER = new PercentEscaper(URL_FORM_PARAMETER_OTHER_SAFE_CHARS, false);
|
||||||
|
|
||||||
|
public static String sanitizeBaseUrl(String theBaseUrl) {
|
||||||
|
return theBaseUrl.replaceAll("[^a-zA-Z0-9:/._-]", "");
|
||||||
|
}
|
||||||
|
|
||||||
public static class UrlParts {
|
public static class UrlParts {
|
||||||
private String myParams;
|
private String myParams;
|
||||||
private String myResourceId;
|
private String myResourceId;
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 3256
|
||||||
|
title: "An occasional concurrency failure in AuthorizationInterceptor has been resolved. Thanks to
|
||||||
|
Martin Visser for reporting and providing a reproducible test case!"
|
|
@ -789,7 +789,12 @@ public class ResponseHighlighterInterceptor {
|
||||||
|
|
||||||
InputStream jsStream = ResponseHighlighterInterceptor.class.getResourceAsStream("ResponseHighlighter.js");
|
InputStream jsStream = ResponseHighlighterInterceptor.class.getResourceAsStream("ResponseHighlighter.js");
|
||||||
String jsStr = jsStream != null ? IOUtils.toString(jsStream, StandardCharsets.UTF_8) : "console.log('ResponseHighlighterInterceptor: javascript theResource not found')";
|
String jsStr = jsStream != null ? IOUtils.toString(jsStream, StandardCharsets.UTF_8) : "console.log('ResponseHighlighterInterceptor: javascript theResource not found')";
|
||||||
jsStr = jsStr.replace("FHIR_BASE", theRequestDetails.getServerBaseForRequest());
|
|
||||||
|
String baseUrl = theRequestDetails.getServerBaseForRequest();
|
||||||
|
|
||||||
|
baseUrl = UrlUtil.sanitizeBaseUrl(baseUrl);
|
||||||
|
|
||||||
|
jsStr = jsStr.replace("FHIR_BASE", baseUrl);
|
||||||
outputBuffer.append("<script type=\"text/javascript\">");
|
outputBuffer.append("<script type=\"text/javascript\">");
|
||||||
outputBuffer.append(jsStr);
|
outputBuffer.append(jsStr);
|
||||||
outputBuffer.append("</script>\n");
|
outputBuffer.append("</script>\n");
|
||||||
|
|
|
@ -398,6 +398,9 @@ class RuleImplOp extends BaseRule /* implements IAuthRule */ {
|
||||||
if (params == null || params.isEmpty()) {
|
if (params == null || params.isEmpty()) {
|
||||||
params = additionalParams;
|
params = additionalParams;
|
||||||
} else {
|
} else {
|
||||||
|
List<RuntimeSearchParam> existingParams = params;
|
||||||
|
params = new ArrayList<>(existingParams.size() + additionalParams.size());
|
||||||
|
params.addAll(existingParams);
|
||||||
params.addAll(additionalParams);
|
params.addAll(additionalParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ import org.hl7.fhir.r4.model.DocumentReference;
|
||||||
import org.hl7.fhir.r4.model.Enumeration;
|
import org.hl7.fhir.r4.model.Enumeration;
|
||||||
import org.hl7.fhir.r4.model.Enumerations;
|
import org.hl7.fhir.r4.model.Enumerations;
|
||||||
import org.hl7.fhir.r4.model.Extension;
|
import org.hl7.fhir.r4.model.Extension;
|
||||||
|
import org.hl7.fhir.r4.model.IdType;
|
||||||
import org.hl7.fhir.r4.model.Identifier;
|
import org.hl7.fhir.r4.model.Identifier;
|
||||||
import org.hl7.fhir.r4.model.MarkdownType;
|
import org.hl7.fhir.r4.model.MarkdownType;
|
||||||
import org.hl7.fhir.r4.model.Medication;
|
import org.hl7.fhir.r4.model.Medication;
|
||||||
|
@ -51,6 +52,10 @@ import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
@ -1427,6 +1432,40 @@ public class FhirTerserR4Test {
|
||||||
assertEquals("cid:device@bundle", elems.get(1).getReferenceElement().getValue());
|
assertEquals("cid:device@bundle", elems.get(1).getReferenceElement().getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConcurrentTerserCalls() throws ExecutionException, InterruptedException {
|
||||||
|
ExecutorService executor = Executors.newFixedThreadPool(10);
|
||||||
|
try {
|
||||||
|
|
||||||
|
FhirContext ctx = FhirContext.forR4();
|
||||||
|
|
||||||
|
List<Future<?>> futures = new ArrayList<>();
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
|
||||||
|
Runnable runnable = () -> {
|
||||||
|
|
||||||
|
Observation observation = new Observation();
|
||||||
|
observation.setSubject(new Reference("Patient/123"));
|
||||||
|
HashSet<String> additionalCompartmentParamNames = new HashSet<>();
|
||||||
|
additionalCompartmentParamNames.add("test");
|
||||||
|
boolean outcome = ctx.newTerser().isSourceInCompartmentForTarget("Patient", observation, new IdType("Patient/123"), additionalCompartmentParamNames);
|
||||||
|
assertTrue(outcome);
|
||||||
|
|
||||||
|
};
|
||||||
|
Future<?> future = executor.submit(runnable);
|
||||||
|
futures.add(future);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var next : futures) {
|
||||||
|
next.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
}finally {
|
||||||
|
executor.shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private List<String> toStrings(List<StringType> theStrings) {
|
private List<String> toStrings(List<StringType> theStrings) {
|
||||||
ArrayList<String> retVal = new ArrayList<>();
|
ArrayList<String> retVal = new ArrayList<>();
|
||||||
|
|
14
pom.xml
14
pom.xml
|
@ -1713,6 +1713,20 @@
|
||||||
<groupId>org.quartz-scheduler</groupId>
|
<groupId>org.quartz-scheduler</groupId>
|
||||||
<artifactId>quartz</artifactId>
|
<artifactId>quartz</artifactId>
|
||||||
<version>2.3.2</version>
|
<version>2.3.2</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>com.zaxxer</groupId>
|
||||||
|
<artifactId>HikariCP-java7</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>com.mchange</groupId>
|
||||||
|
<artifactId>c3p0</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>com.mchange</groupId>
|
||||||
|
<artifactId>mchange-commons-java</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
|
|
Loading…
Reference in New Issue