diff --git a/i18n-coverage-table.png b/i18n-coverage-table.png index 7b00d33d6..1d5306247 100644 Binary files a/i18n-coverage-table.png and b/i18n-coverage-table.png differ diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/analytics/PackageVisitor.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/analytics/PackageVisitor.java index 2116caa6d..64a1f0055 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/analytics/PackageVisitor.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/analytics/PackageVisitor.java @@ -14,11 +14,11 @@ import javax.xml.parsers.ParserConfigurationException; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.r5.utils.EOperationOutcome; -import org.hl7.fhir.utilities.SimpleHTTPClient; -import org.hl7.fhir.utilities.SimpleHTTPClient.HTTPResult; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.filesystem.ManagedFileAccess; +import org.hl7.fhir.utilities.http.HTTPResult; +import org.hl7.fhir.utilities.http.ManagedWebAccess; import org.hl7.fhir.utilities.json.model.JsonArray; import org.hl7.fhir.utilities.json.model.JsonObject; import org.hl7.fhir.utilities.json.parser.JsonParser; @@ -233,8 +233,8 @@ public class PackageVisitor { JsonObject manifest = JsonParser.parseObjectFromUrl(repo+"/package.manifest.json"); File co = ManagedFileAccess.file(Utilities.path(cache, pid+"."+manifest.asString("date")+".tgz")); if (!co.exists()) { - SimpleHTTPClient fetcher = new SimpleHTTPClient(); - HTTPResult res = fetcher.get(repo+"/package.tgz?nocache=" + System.currentTimeMillis()); + + HTTPResult res = ManagedWebAccess.get(repo+"/package.tgz?nocache=" + System.currentTimeMillis()); res.checkThrowException(); TextFile.bytesToFile(res.getContent(), co); } @@ -330,8 +330,8 @@ public class PackageVisitor { private void processFeed(Set list, String str) throws IOException, ParserConfigurationException, SAXException { System.out.println("Feed "+str); try { - SimpleHTTPClient fetcher = new SimpleHTTPClient(); - HTTPResult res = fetcher.get(str+"?nocache=" + System.currentTimeMillis()); + + HTTPResult res = ManagedWebAccess.get(str+"?nocache=" + System.currentTimeMillis()); res.checkThrowException(); Document xml = XMLUtil.parseToDom(res.getContent()); for (Element channel : XMLUtil.getNamedChildren(xml.getDocumentElement(), "channel")) { diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/CKMImporter.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/CKMImporter.java index 03b39aab9..881bad4a9 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/CKMImporter.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/CKMImporter.java @@ -40,11 +40,11 @@ import javax.xml.parsers.DocumentBuilderFactory; import org.hl7.fhir.convertors.misc.adl.ADLImporter; -import org.hl7.fhir.utilities.SimpleHTTPClient; -import org.hl7.fhir.utilities.SimpleHTTPClient.HTTPResult; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.filesystem.ManagedFileAccess; +import org.hl7.fhir.utilities.http.HTTPResult; +import org.hl7.fhir.utilities.http.ManagedWebAccess; import org.hl7.fhir.utilities.xml.XMLUtil; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -125,8 +125,8 @@ public class CKMImporter { } private Document loadXml(String address) throws Exception { - SimpleHTTPClient http = new SimpleHTTPClient(); - HTTPResult res = http.get(address, "application/xml"); + + HTTPResult res = ManagedWebAccess.get(address, "application/xml"); res.checkThrowException(); InputStream xml = new ByteArrayInputStream(res.getContent()); diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/ICD11Generator.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/ICD11Generator.java index e2e402bce..2999ec012 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/ICD11Generator.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/misc/ICD11Generator.java @@ -25,10 +25,10 @@ import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent; import org.hl7.fhir.r4.model.ValueSet.FilterOperator; import org.hl7.fhir.r4.terminologies.CodeSystemUtilities; import org.hl7.fhir.r4.utils.ToolingExtensions; -import org.hl7.fhir.utilities.SimpleHTTPClient; -import org.hl7.fhir.utilities.SimpleHTTPClient.HTTPResult; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.filesystem.ManagedFileAccess; +import org.hl7.fhir.utilities.http.HTTPResult; +import org.hl7.fhir.utilities.http.ManagedWebAccess; import org.hl7.fhir.utilities.json.model.JsonElement; import org.hl7.fhir.utilities.json.model.JsonObject; import org.hl7.fhir.utilities.json.parser.JsonParser; @@ -395,10 +395,7 @@ public class ICD11Generator { private JsonObject fetchJson(String source) throws IOException { - SimpleHTTPClient http = new SimpleHTTPClient(); - http.addHeader("API-Version", "v2"); - http.addHeader("Accept-Language", "en"); - HTTPResult res = http.get(source, "application/json"); + HTTPResult res = ManagedWebAccess.builder().withAccept("application/json").withHeader("API-Version", "v2").withHeader("Accept-Language", "en").get(source); res.checkThrowException(); return JsonParser.parseObject(res.getContent()); } diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/conformance/ProfileComparer.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/conformance/ProfileComparer.java index df0179d52..f9d34478d 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/conformance/ProfileComparer.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/conformance/ProfileComparer.java @@ -66,11 +66,11 @@ import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome; import org.hl7.fhir.r4.utils.DefinitionNavigator; import org.hl7.fhir.r4.utils.ToolingExtensions; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; -import org.hl7.fhir.utilities.SimpleHTTPClient; -import org.hl7.fhir.utilities.SimpleHTTPClient.HTTPResult; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.filesystem.ManagedFileAccess; +import org.hl7.fhir.utilities.http.HTTPResult; +import org.hl7.fhir.utilities.http.ManagedWebAccess; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage.Source; @@ -1383,8 +1383,8 @@ public class ProfileComparer { File f = ManagedFileAccess.file(local); if (f.exists()) return TextFile.fileToString(f); - SimpleHTTPClient http = new SimpleHTTPClient(); - HTTPResult res = http.get(source); + + HTTPResult res = ManagedWebAccess.get(source); res.checkThrowException(); String result = TextFile.bytesToString(res.getContent()); TextFile.stringToFile(result, f); diff --git a/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/terminologies/TerminologyCacheManager.java b/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/terminologies/TerminologyCacheManager.java index b481fe422..68b94ed83 100644 --- a/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/terminologies/TerminologyCacheManager.java +++ b/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/terminologies/TerminologyCacheManager.java @@ -22,13 +22,13 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; -import org.hl7.fhir.utilities.SimpleHTTPClient; -import org.hl7.fhir.utilities.SimpleHTTPClient.HTTPResult; import org.hl7.fhir.utilities.IniFile; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.filesystem.ManagedFileAccess; +import org.hl7.fhir.utilities.http.HTTPResult; +import org.hl7.fhir.utilities.http.ManagedWebAccess; public class TerminologyCacheManager { @@ -87,8 +87,7 @@ public class TerminologyCacheManager { try { System.out.println("Initialise terminology cache from " + source); - SimpleHTTPClient http = new SimpleHTTPClient(); - HTTPResult res = http.get(source + "?nocache=" + System.currentTimeMillis()); + HTTPResult res = ManagedWebAccess.get(source + "?nocache=" + System.currentTimeMillis()); res.checkThrowException(); unzip(new ByteArrayInputStream(res.getContent()), cacheFolder); } catch (Exception e) { @@ -156,11 +155,10 @@ public class TerminologyCacheManager { // post it to String url = "https://tx.fhir.org/post/tx-cache/" + ghOrg + "/" + ghRepo + "/" + ghBranch + ".zip"; System.out.println("Sending tx-cache to " + url + " (" + Utilities.describeSize(bs.toByteArray().length) + ")"); - SimpleHTTPClient http = new SimpleHTTPClient(); - http.setAuthenticationMode(SimpleHTTPClient.AuthenticationMode.BASIC); - http.setUsername(token.substring(0, token.indexOf(':'))); - http.setPassword(token.substring(token.indexOf(':') + 1)); - HTTPResult res = http.put(url, "application/zip", bs.toByteArray(), null); // accept doesn't matter + + HTTPResult res = ManagedWebAccess.builder() + .withBasicAuth(token.substring(0, token.indexOf(':')), token.substring(token.indexOf(':') + 1)) + .withAccept("application/zip").put(url, bs.toByteArray(), null); if (res.getCode() >= 300) { System.out.println("sending cache failed: " + res.getCode()); } else { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/SHLParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/SHLParser.java index e47867691..bbbf0e851 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/SHLParser.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/SHLParser.java @@ -29,11 +29,11 @@ import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.formats.IParser.OutputStyle; import org.hl7.fhir.r5.test.utils.TestingUtilities; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; -import org.hl7.fhir.utilities.SimpleHTTPClient; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; -import org.hl7.fhir.utilities.SimpleHTTPClient.HTTPResult; +import org.hl7.fhir.utilities.http.HTTPResult; +import org.hl7.fhir.utilities.http.ManagedWebAccess; import org.hl7.fhir.utilities.json.model.JsonArray; import org.hl7.fhir.utilities.json.model.JsonElement; import org.hl7.fhir.utilities.json.model.JsonElementType; @@ -287,9 +287,7 @@ public class SHLParser extends ParserBase { private HTTPResult fetchFile(String url, String ct) throws IOException { - SimpleHTTPClient fetcher = new SimpleHTTPClient(); - fetcher.addHeader("Accept", ct); - HTTPResult res = fetcher.get(url); + HTTPResult res = ManagedWebAccess.get(url, ct); res.checkThrowException(); return res; } @@ -298,10 +296,10 @@ public class SHLParser extends ParserBase { if (testMode) { return new HTTPResult(url, 200, "OK", "application/json", TextFile.streamToBytes(TestingUtilities.loadTestResourceStream("validator", "shlink.manifest.json"))); } - SimpleHTTPClient fetcher = new SimpleHTTPClient(); + JsonObject j = new JsonObject(); j.add("recipient", "FHIR Validator"); - HTTPResult res = fetcher.post(url, "application/json", org.hl7.fhir.utilities.json.parser.JsonParser.composeBytes(j), "application/json"); + HTTPResult res = ManagedWebAccess.post(url, org.hl7.fhir.utilities.json.parser.JsonParser.composeBytes(j), "application/json", "application/json"); res.checkThrowException(); return res; } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java index 31cfd4900..bdddf9b10 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java @@ -294,7 +294,7 @@ public class DataRenderer extends Renderer implements CodeResolver { if (system.equals("http://loinc.org")) return (context.formatMessage(RenderingContext.DATA_REND_LOINC)); if (system.startsWith("http://snomed.info")) - return (context.formatMessage(RenderingContext.DATA_REND_SNOWMED)); + return (context.formatMessage(RenderingContext.DATA_REND_SNOMED)); if (system.equals("http://www.nlm.nih.gov/research/umls/rxnorm")) return (context.formatMessage(RenderingContext.DATA_REND_RXNORM)); if (system.equals("http://hl7.org/fhir/sid/icd-9")) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/TerminologyCacheManager.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/TerminologyCacheManager.java index fc3ea158b..3e63ac0a8 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/TerminologyCacheManager.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/TerminologyCacheManager.java @@ -22,13 +22,13 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; -import org.hl7.fhir.utilities.SimpleHTTPClient; -import org.hl7.fhir.utilities.SimpleHTTPClient.HTTPResult; import org.hl7.fhir.utilities.IniFile; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.filesystem.ManagedFileAccess; +import org.hl7.fhir.utilities.http.HTTPResult; +import org.hl7.fhir.utilities.http.ManagedWebAccess; public class TerminologyCacheManager { @@ -86,8 +86,7 @@ public class TerminologyCacheManager { try { System.out.println("Initialise terminology cache from "+source); - SimpleHTTPClient http = new SimpleHTTPClient(); - HTTPResult res = http.get(source+"?nocache=" + System.currentTimeMillis()); + HTTPResult res = ManagedWebAccess.get(source+"?nocache=" + System.currentTimeMillis()); res.checkThrowException(); unzip(new ByteArrayInputStream(res.getContent()), cacheFolder); } catch (Exception e) { @@ -157,11 +156,10 @@ public class TerminologyCacheManager { // post it to String url = "https://tx.fhir.org/post/tx-cache/"+ghOrg+"/"+ghRepo+"/"+ghBranch+".zip"; System.out.println("Sending tx-cache to "+url+" ("+Utilities.describeSize(bs.toByteArray().length)+")"); - SimpleHTTPClient http = new SimpleHTTPClient(); - http.setAuthenticationMode(SimpleHTTPClient.AuthenticationMode.BASIC); - http.setUsername(token.substring(0, token.indexOf(':'))); - http.setPassword(token.substring(token.indexOf(':')+1)); - HTTPResult res = http.put(url, "application/zip", bs.toByteArray(), null); // accept doesn't matter + HTTPResult res = ManagedWebAccess.builder() + .withBasicAuth(token.substring(0, token.indexOf(':')), token.substring(token.indexOf(':') + 1)) + .withAccept("application/zip").put(url, bs.toByteArray(), null); + if (res.getCode() >= 300) { System.out.println("sending cache failed: "+res.getCode()); } else { diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/HTTPAuthenticationMode.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/HTTPAuthenticationMode.java new file mode 100644 index 000000000..401c1cd15 --- /dev/null +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/HTTPAuthenticationMode.java @@ -0,0 +1,7 @@ +package org.hl7.fhir.utilities.http; + +public enum HTTPAuthenticationMode { + NONE, + BASIC, + TOKEN +} \ No newline at end of file diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/HTTPResult.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/HTTPResult.java new file mode 100644 index 000000000..0a3986ec1 --- /dev/null +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/HTTPResult.java @@ -0,0 +1,62 @@ +package org.hl7.fhir.utilities.http; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import org.hl7.fhir.utilities.TextFile; +import org.hl7.fhir.utilities.Utilities; + +public class HTTPResult { + private int code; + private String contentType; + private byte[] content; + private String source; + private String message; + + + public HTTPResult(String source, int code, String message, String contentType, byte[] content) { + super(); + this.source = source; + this.code = code; + this.contentType = contentType; + this.content = content; + this.message = message; + } + + public int getCode() { + return code; + } + public String getContentType() { + return contentType; + } + public byte[] getContent() { + return content; + } + + public String getSource() { + return source; + } + + public void checkThrowException() throws IOException { + if (code >= 300) { + String filename = Utilities.path("[tmp]", "http-log", "fhir-http-"+(SimpleHTTPClient.nextCounter())+".log"); + if (content == null || content.length == 0) { + HTTPResultException exception = new HTTPResultException(code, message, source, null); + throw new IOException(exception.message, exception); + } else { + Utilities.createDirectory(Utilities.path("[tmp]", "http-log")); + TextFile.bytesToFile(content, filename); + HTTPResultException exception = new HTTPResultException(code, message, source, filename); + throw new IOException(exception.message, exception); + } + } + } + + public String getMessage() { + return message; + } + + public String getContentAsString() { + return new String(content, StandardCharsets.UTF_8); + } +} \ No newline at end of file diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/HTTPResultException.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/HTTPResultException.java new file mode 100644 index 000000000..dce4d00e5 --- /dev/null +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/HTTPResultException.java @@ -0,0 +1,24 @@ +package org.hl7.fhir.utilities.http; + +public class HTTPResultException extends Exception{ + public final int httpCode; + + public final String message; + + public final String url; + public final String logPath; + + public HTTPResultException(int httpCode, String message, String url, String logPath) { + this.httpCode = httpCode; + this.message = message; + this.url = url; + this.logPath = logPath; + } + + public String getMessage() { + return "Invalid HTTP response "+httpCode+" from "+url+" ("+message+") (" + ( + logPath != null ? "Response in " + logPath : "No response content") + + ")"; + } + +} \ No newline at end of file diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/ManagedWebAccess.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/ManagedWebAccess.java new file mode 100644 index 000000000..6c90c3a44 --- /dev/null +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/ManagedWebAccess.java @@ -0,0 +1,131 @@ +package org.hl7.fhir.utilities.http; + +/* + Copyright (c) 2011+, HL7, Inc. + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of HL7 nor the names of its contributors may be used to + endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + */ + + + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.hl7.fhir.utilities.Utilities; + +/** + * see security.md - manages access to the local file system by the FHIR HAPI Core library + * + * By using accessPolicy, allowedDomains and accessor, a host java application can control + * whether this library has direct access to the web (and which domains it is allowed to access), + * or whether the host application provides controlled access, or whether no access is allowed at all + * (in which case other information providers need to be provided) + * + * @author Grahame + * + */ +public class ManagedWebAccess { + + public interface IWebAccessor { + HTTPResult get(String url, String accept, Map headers) throws IOException; + HTTPResult post(String url, byte[] bytes, String contentType, String accept, Map headers) throws IOException; + HTTPResult put(String url, byte[] bytes, String contentType, String accept, Map headers) throws IOException; + } + + public enum WebAccessPolicy { + DIRECT, // open access to the local file system, though access can be restricted only to files under the paths in AllowedPaths + MANAGED, // no access except by the FileSystemProxyProvider + PROHIBITED, // no access at all to File() services + } + + private static WebAccessPolicy accessPolicy = WebAccessPolicy.DIRECT; // for legacy reasons + private static List allowedDomains = new ArrayList<>(); + private static IWebAccessor accessor; + private static String userAgent; + + + public static WebAccessPolicy getAccessPolicy() { + return accessPolicy; + } + + public static void setAccessPolicy(WebAccessPolicy accessPolicy) { + ManagedWebAccess.accessPolicy = accessPolicy; + } + + static boolean inAllowedPaths(String pathname) { + if (allowedDomains.isEmpty()) { + return true; + } + for (String s : allowedDomains) { + if (pathname.startsWith(s)) { + return true; + } + } + return false; + } + + public static String getUserAgent() { + return userAgent; + } + + public static void setUserAgent(String userAgent) { + ManagedWebAccess.userAgent = userAgent; + } + + public static IWebAccessor getAccessor() { + return accessor; + } + + public static ManagedWebAccessBuilder builder() { + return new ManagedWebAccessBuilder(userAgent); + } + + public static HTTPResult get(String url) throws IOException { + return builder().get(url); + } + + public static HTTPResult get(String url, String accept) throws IOException { + return builder().withAccept(accept).get(url); + } + + public static HTTPResult post(String url, byte[] content, String contentType, String accept) throws IOException { + return builder().withAccept(accept).post(url, content, contentType); + } + + + public static HTTPResult put(String url, byte[] content, String contentType, String accept) throws IOException { + return builder().withAccept(accept).put(url, content, contentType); + } + +} \ No newline at end of file diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/ManagedWebAccessBuilder.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/ManagedWebAccessBuilder.java new file mode 100644 index 000000000..5eac395c6 --- /dev/null +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/ManagedWebAccessBuilder.java @@ -0,0 +1,126 @@ +package org.hl7.fhir.utilities.http; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; + + +public class ManagedWebAccessBuilder { + + private String userAgent; + private HTTPAuthenticationMode authenticationMode; + private String username; + private String password; + private String token; + private String accept; + private Map headers = new HashMap(); + + public ManagedWebAccessBuilder(String userAgent) { + this.userAgent = userAgent; + } + + public ManagedWebAccessBuilder withAccept(String accept) { + this.accept = accept; + return this; + } + + public ManagedWebAccessBuilder withHeader(String name, String value) { + headers.put(name, value); + return this; + } + + public ManagedWebAccessBuilder withBasicAuth(String username, String password) { + this.authenticationMode = HTTPAuthenticationMode.BASIC; + this.username = username; + this.password = password; + return this; + } + + public ManagedWebAccessBuilder withToken(String token) { + this.authenticationMode = HTTPAuthenticationMode.TOKEN; + this.token = token; + return this; + } + + private Map headers() { + Map headers = new HashMap(); + headers.putAll(this.headers); + if (authenticationMode == HTTPAuthenticationMode.TOKEN) { + headers.put("Authorization", "Bearer " + token); + } else if (authenticationMode == HTTPAuthenticationMode.BASIC) { + String auth = username+":"+password; + byte[] encodedAuth = Base64.getEncoder().encode(auth.getBytes(StandardCharsets.UTF_8)); + headers.put("Authorization", "Basic " + new String(encodedAuth)); + } + + if (userAgent != null) { + headers.put("User-Agent", userAgent); + } + + return headers; + } + + private SimpleHTTPClient setupClient(String url) throws IOException { + if (!ManagedWebAccess.inAllowedPaths(url)) { + throw new IOException("The pathname '"+url+"' cannot be accessed by policy"); + } + SimpleHTTPClient client = new SimpleHTTPClient(); + if (userAgent != null) { + client.addHeader("User-Agent", userAgent); + } + if (username != null || token != null) { + client.setUsername(username); + client.setPassword(password); + client.setToken(token); + client.setAuthenticationMode(authenticationMode); + } + return client; + } + + + public HTTPResult get(String url) throws IOException { + switch (ManagedWebAccess.getAccessPolicy()) { + case DIRECT: + SimpleHTTPClient client = setupClient(url); + return client.get(url, accept); + case MANAGED: + return ManagedWebAccess.getAccessor().get(url, accept, headers()); + case PROHIBITED: + throw new IOException("Access to the internet is not allowed by local security policy"); + default: + throw new IOException("Internal Error"); + } + } + + + public HTTPResult post(String url, byte[] content, String contentType) throws IOException { + switch (ManagedWebAccess.getAccessPolicy()) { + case DIRECT: + SimpleHTTPClient client = setupClient(url); + return client.post(url, contentType, content, accept); + case MANAGED: + return ManagedWebAccess.getAccessor().post(url, content, contentType, accept, headers()); + case PROHIBITED: + throw new IOException("Access to the internet is not allowed by local security policy"); + default: + throw new IOException("Internal Error"); + } + } + + public HTTPResult put(String url, byte[] content, String contentType) throws IOException { + switch (ManagedWebAccess.getAccessPolicy()) { + case DIRECT: + SimpleHTTPClient client = setupClient(url); + return client.put(url, contentType, content, accept); + case MANAGED: + return ManagedWebAccess.getAccessor().put(url, content, contentType, accept, headers()); + case PROHIBITED: + throw new IOException("Access to the internet is not allowed by local security policy"); + default: + throw new IOException("Internal Error"); + } + } + +} diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/SimpleHTTPClient.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/SimpleHTTPClient.java similarity index 66% rename from org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/SimpleHTTPClient.java rename to org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/SimpleHTTPClient.java index 56461c690..ad3f5c7d5 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/SimpleHTTPClient.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/SimpleHTTPClient.java @@ -1,4 +1,4 @@ -package org.hl7.fhir.utilities; +package org.hl7.fhir.utilities.http; import java.io.IOException; import java.net.HttpURLConnection; @@ -12,6 +12,7 @@ import java.util.List; import java.util.Map; import org.hl7.fhir.exceptions.FHIRException; +import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.settings.FhirSettings; import lombok.Getter; @@ -19,11 +20,6 @@ import lombok.Setter; public class SimpleHTTPClient { - public enum AuthenticationMode { - NONE, - BASIC, - TOKEN - } public static class Header { private String name; @@ -44,88 +40,10 @@ public class SimpleHTTPClient { private static final int MAX_REDIRECTS = 5; private static int counter = 1; - public static class HTTPResultException extends Exception{ - public final int httpCode; - - public final String message; - - public final String url; - public final String logPath; - - public HTTPResultException(int httpCode, String message, String url, String logPath) { - this.httpCode = httpCode; - this.message = message; - this.url = url; - this.logPath = logPath; - } - - public String getMessage() { - return "Invalid HTTP response "+httpCode+" from "+url+" ("+message+") (" + ( - logPath != null ? "Response in " + logPath : "No response content") - + ")"; - } - - } - - public static class HTTPResult { - private int code; - private String contentType; - private byte[] content; - private String source; - private String message; - - - public HTTPResult(String source, int code, String message, String contentType, byte[] content) { - super(); - this.source = source; - this.code = code; - this.contentType = contentType; - this.content = content; - this.message = message; - } - - public int getCode() { - return code; - } - public String getContentType() { - return contentType; - } - public byte[] getContent() { - return content; - } - - public String getSource() { - return source; - } - - public void checkThrowException() throws IOException { - if (code >= 300) { - String filename = Utilities.path("[tmp]", "http-log", "fhir-http-"+(++counter)+".log"); - if (content == null || content.length == 0) { - HTTPResultException exception = new HTTPResultException(code, message, source, null); - throw new IOException(exception.message, exception); - } else { - Utilities.createDirectory(Utilities.path("[tmp]", "http-log")); - TextFile.bytesToFile(content, filename); - HTTPResultException exception = new HTTPResultException(code, message, source, filename); - throw new IOException(exception.message, exception); - } - } - } - - public String getMessage() { - return message; - } - - public String getContentAsString() { - return new String(content, StandardCharsets.UTF_8); - } - } - private List
headers = new ArrayList<>(); @Getter @Setter - private AuthenticationMode authenticationMode; + private HTTPAuthenticationMode authenticationMode; @Getter @Setter private String username; @@ -202,9 +120,9 @@ public class SimpleHTTPClient { private void setAuthenticationHeader(HttpURLConnection c) { String authHeaderValue = null; - if (authenticationMode == AuthenticationMode.TOKEN) { + if (authenticationMode == HTTPAuthenticationMode.TOKEN) { authHeaderValue = "Bearer " + new String(token); - } else if (authenticationMode == AuthenticationMode.BASIC) { + } else if (authenticationMode == HTTPAuthenticationMode.BASIC) { String auth = username+":"+password; byte[] encodedAuth = Base64.getEncoder().encode(auth.getBytes(StandardCharsets.UTF_8)); authHeaderValue = "Basic " + new String(encodedAuth); @@ -254,5 +172,9 @@ public class SimpleHTTPClient { return new HTTPResult(url, c.getResponseCode(), c.getResponseMessage(), c.getRequestProperty("Content-Type"), TextFile.streamToBytes(c.getResponseCode() >= 400 ? c.getErrorStream() : c.getInputStream())); } + public static int nextCounter() { + return ++counter; + } + } \ No newline at end of file diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/RenderingI18nContext.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/RenderingI18nContext.java index 01a2d927e..7216385b1 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/RenderingI18nContext.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/RenderingI18nContext.java @@ -223,7 +223,7 @@ public class RenderingI18nContext extends I18nBase { public static final String DATA_REND_MKDWN_LNK = "DATA_REND_MKDWN_LNK"; public static final String DATA_REND_UNRD_EX = "DATA_REND_UNRD_EX"; public static final String DATA_REND_LOINC = "DATA_REND_LOINC"; - public static final String DATA_REND_SNOWMED = "DATA_REND_SNOWMED"; + public static final String DATA_REND_SNOMED = "DATA_REND_SNOMED"; public static final String DATA_REND_RXNORM = "DATA_REND_RXNORM"; public static final String DATA_REND_ICD = "DATA_REND_ICD"; public static final String DATA_REND_DICOM = "DATA_REND_DICOM"; diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/json/JsonTrackingParser.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/json/JsonTrackingParser.java index 325c02617..893aba96c 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/json/JsonTrackingParser.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/json/JsonTrackingParser.java @@ -40,10 +40,10 @@ import java.nio.charset.StandardCharsets; import java.util.Map; import java.util.Stack; -import org.hl7.fhir.utilities.SimpleHTTPClient; -import org.hl7.fhir.utilities.SimpleHTTPClient.HTTPResult; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; +import org.hl7.fhir.utilities.http.HTTPResult; +import org.hl7.fhir.utilities.http.ManagedWebAccess; import com.google.gson.Gson; import com.google.gson.GsonBuilder; @@ -724,15 +724,13 @@ public class JsonTrackingParser { } public static JsonObject fetchJson(String source) throws IOException { - SimpleHTTPClient fetcher = new SimpleHTTPClient(); - HTTPResult res = fetcher.get(source+"?nocache=" + System.currentTimeMillis()); + HTTPResult res = ManagedWebAccess.get(source+"?nocache=" + System.currentTimeMillis(), "application/json, application/fhir+json"); res.checkThrowException(); return parseJson(res.getContent()); } public static JsonArray fetchJsonArray(String source) throws IOException { - SimpleHTTPClient fetcher = new SimpleHTTPClient(); - HTTPResult res = fetcher.get(source+"?nocache=" + System.currentTimeMillis()); + HTTPResult res = ManagedWebAccess.get(source+"?nocache=" + System.currentTimeMillis(), "application/json, application/fhir+json"); res.checkThrowException(); return parseJsonArray(res.getContent()); } diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/json/parser/JsonParser.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/json/parser/JsonParser.java index 3bf7e9f37..f795b6bdf 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/json/parser/JsonParser.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/json/parser/JsonParser.java @@ -8,11 +8,11 @@ import java.io.OutputStream; import java.nio.charset.StandardCharsets; import java.util.List; -import org.hl7.fhir.utilities.SimpleHTTPClient; -import org.hl7.fhir.utilities.SimpleHTTPClient.HTTPResult; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.filesystem.ManagedFileAccess; +import org.hl7.fhir.utilities.http.HTTPResult; +import org.hl7.fhir.utilities.http.ManagedWebAccess; import org.hl7.fhir.utilities.json.JsonException; import org.hl7.fhir.utilities.json.model.JsonArray; import org.hl7.fhir.utilities.json.model.JsonBoolean; @@ -671,10 +671,8 @@ public class JsonParser { } private static byte[] fetch(String source) throws IOException { - SimpleHTTPClient fetcher = new SimpleHTTPClient(); - fetcher.addHeader("Accept", "application/json, application/fhir+json"); String murl = source.contains("?") ? source+"&nocache=" + System.currentTimeMillis() : source+"?nocache=" + System.currentTimeMillis(); - HTTPResult res = fetcher.get(murl); + HTTPResult res = ManagedWebAccess.get(murl, "application/json, application/fhir+json"); res.checkThrowException(); return res.getContent(); } diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/FilesystemPackageCacheManager.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/FilesystemPackageCacheManager.java index b326fcc40..c3ad924f2 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/FilesystemPackageCacheManager.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/FilesystemPackageCacheManager.java @@ -27,12 +27,12 @@ import lombok.With; import org.apache.commons.io.FileUtils; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.utilities.IniFile; -import org.hl7.fhir.utilities.SimpleHTTPClient; -import org.hl7.fhir.utilities.SimpleHTTPClient.HTTPResult; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.filesystem.ManagedFileAccess; +import org.hl7.fhir.utilities.http.HTTPResult; +import org.hl7.fhir.utilities.http.ManagedWebAccess; import org.hl7.fhir.utilities.json.model.JsonArray; import org.hl7.fhir.utilities.json.model.JsonElement; import org.hl7.fhir.utilities.json.model.JsonObject; @@ -658,8 +658,7 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple private InputStream fetchFromUrlSpecific(String source, boolean optional) throws FHIRException { try { - SimpleHTTPClient http = new SimpleHTTPClient(); - HTTPResult res = http.get(source); + HTTPResult res = ManagedWebAccess.get(source); res.checkThrowException(); return new ByteArrayInputStream(res.getContent()); } catch (Exception e) { @@ -803,9 +802,8 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple } private void loadFromBuildServer() throws IOException { - SimpleHTTPClient http = new SimpleHTTPClient(); - HTTPResult res = http.get("https://build.fhir.org/ig/qas.json?nocache=" + System.currentTimeMillis()); + HTTPResult res = ManagedWebAccess.get("https://build.fhir.org/ig/qas.json?nocache=" + System.currentTimeMillis()); res.checkThrowException(); buildInfo = (JsonArray) JsonParser.parse(TextFile.bytesToString(res.getContent())); diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackage.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackage.java index ee64726f5..387240cdd 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackage.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackage.java @@ -68,11 +68,11 @@ import org.apache.commons.compress.compressors.gzip.GzipParameters; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.utilities.ByteProvider; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; -import org.hl7.fhir.utilities.SimpleHTTPClient; -import org.hl7.fhir.utilities.SimpleHTTPClient.HTTPResult; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.filesystem.ManagedFileAccess; +import org.hl7.fhir.utilities.http.HTTPResult; +import org.hl7.fhir.utilities.http.ManagedWebAccess; import org.hl7.fhir.utilities.json.JsonException; import org.hl7.fhir.utilities.json.model.JsonArray; import org.hl7.fhir.utilities.json.model.JsonElement; @@ -1443,8 +1443,7 @@ public class NpmPackage { } public static NpmPackage fromUrl(String source) throws IOException { - SimpleHTTPClient fetcher = new SimpleHTTPClient(); - HTTPResult res = fetcher.get(source+"?nocache=" + System.currentTimeMillis()); + HTTPResult res = ManagedWebAccess.get(source+"?nocache=" + System.currentTimeMillis()); res.checkThrowException(); return fromPackage(new ByteArrayInputStream(res.getContent())); } diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageClient.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageClient.java index 0728243bc..1dbab8248 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageClient.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageClient.java @@ -18,11 +18,13 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; -import org.hl7.fhir.utilities.SimpleHTTPClient; -import org.hl7.fhir.utilities.SimpleHTTPClient.HTTPResult; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; +import org.hl7.fhir.utilities.http.HTTPAuthenticationMode; +import org.hl7.fhir.utilities.http.HTTPResult; +import org.hl7.fhir.utilities.http.ManagedWebAccess; +import org.hl7.fhir.utilities.http.ManagedWebAccessBuilder; import org.hl7.fhir.utilities.json.model.JsonArray; import org.hl7.fhir.utilities.json.model.JsonObject; import org.hl7.fhir.utilities.json.model.JsonProperty; @@ -174,22 +176,17 @@ public class PackageClient { } private InputStream fetchUrl(String source, String accept) throws IOException { - SimpleHTTPClient http = getSimpleHTTPClient(); - HTTPResult res = http.get(source, accept); + ManagedWebAccessBuilder client = ManagedWebAccess.builder().withAccept(accept); + if (server.getAuthenticationMode() == HTTPAuthenticationMode.TOKEN) { + client.withToken(server.getToken()); + } else if (server.getAuthenticationMode() == HTTPAuthenticationMode.BASIC) { + client.withBasicAuth(server.getUsername(), server.getPassword()); + } + HTTPResult res = client.get(source); res.checkThrowException(); return new ByteArrayInputStream(res.getContent()); } - @Nonnull - private SimpleHTTPClient getSimpleHTTPClient() { - SimpleHTTPClient client = new SimpleHTTPClient(); - client.setAuthenticationMode(server.getAuthenticationMode()); - client.setUsername(server.getUsername()); - client.setPassword(server.getPassword()); - client.setToken(server.getToken()); - return client; - } - private JsonObject fetchJson(String source) throws IOException { String src = TextFile.streamToString(fetchUrl(source, "application/json")); //System.out.println(src); diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageServer.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageServer.java index 22b1143c4..3a343eed1 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageServer.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageServer.java @@ -6,7 +6,8 @@ import java.util.stream.Collectors; import javax.annotation.Nullable; -import org.hl7.fhir.utilities.SimpleHTTPClient; +import org.hl7.fhir.utilities.http.HTTPAuthenticationMode; +import org.hl7.fhir.utilities.http.SimpleHTTPClient; import org.hl7.fhir.utilities.settings.FhirSettings; import org.hl7.fhir.utilities.settings.PackageServerPOJO; @@ -22,14 +23,14 @@ public class PackageServer { public PackageServer(String url) { this.url = url; - authenticationMode = SimpleHTTPClient.AuthenticationMode.NONE; + authenticationMode = HTTPAuthenticationMode.NONE; serverType = PackageServerType.FHIR; } private String url; @Getter - private SimpleHTTPClient.AuthenticationMode authenticationMode; + private HTTPAuthenticationMode authenticationMode; @Getter private PackageServerType serverType; @@ -76,9 +77,9 @@ public class PackageServer { } @Nullable - private static SimpleHTTPClient.AuthenticationMode getModeFromPOJO(PackageServerPOJO pojo) { - if (pojo.getAuthenticationType().equalsIgnoreCase("basic")) return SimpleHTTPClient.AuthenticationMode.BASIC; - if (pojo.getAuthenticationType().equalsIgnoreCase("token")) return SimpleHTTPClient.AuthenticationMode.TOKEN; + private static HTTPAuthenticationMode getModeFromPOJO(PackageServerPOJO pojo) { + if (pojo.getAuthenticationType().equalsIgnoreCase("basic")) return HTTPAuthenticationMode.BASIC; + if (pojo.getAuthenticationType().equalsIgnoreCase("token")) return HTTPAuthenticationMode.TOKEN; return null; } @@ -103,7 +104,7 @@ public class PackageServer { return packageServer; } - public PackageServer withAuthenticationMode( SimpleHTTPClient.AuthenticationMode mode) { + public PackageServer withAuthenticationMode(HTTPAuthenticationMode mode) { PackageServer packageServer = this.copy(); packageServer.authenticationMode = mode; return packageServer; diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/settings/FhirSettings.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/settings/FhirSettings.java index 0509041f1..ac1bc04f4 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/settings/FhirSettings.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/settings/FhirSettings.java @@ -135,6 +135,12 @@ public class FhirSettings { : instance.fhirSettings.getProhibitNetworkAccess(); } + /** + * See ManagedWebAccess and use that to control network access + * + * @param value + */ + @Deprecated public static void setProhibitNetworkAccess(boolean value) { prohibitNetworkAccess = value; } diff --git a/org.hl7.fhir.utilities/src/main/resources/rendering-phrases.properties b/org.hl7.fhir.utilities/src/main/resources/rendering-phrases.properties index 8c2808158..8296f40d2 100644 --- a/org.hl7.fhir.utilities/src/main/resources/rendering-phrases.properties +++ b/org.hl7.fhir.utilities/src/main/resources/rendering-phrases.properties @@ -230,7 +230,7 @@ CONC_MAP_PROP = Properties DATA_REND_MKDWN_LNK = Unable to resolve markdown link DATA_REND_UNRD_EX = WARNING: Unrenderable Modifier Extension! DATA_REND_LOINC = LOINC -DATA_REND_SNOWMED = SNOWMED CT +DATA_REND_SNOMED = SNOMED CT DATA_REND_RXNORM = RxNorm DATA_REND_ICD = ICD-9 DATA_REND_DICOM = DICOM diff --git a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/SimpleHTTPClientTest.java b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/SimpleHTTPClientTest.java index d2fe2e6c9..866894056 100644 --- a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/SimpleHTTPClientTest.java +++ b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/SimpleHTTPClientTest.java @@ -4,6 +4,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; +import org.hl7.fhir.utilities.http.HTTPResult; +import org.hl7.fhir.utilities.http.SimpleHTTPClient; import org.junit.jupiter.api.Test; public class SimpleHTTPClientTest { @@ -13,7 +15,7 @@ public class SimpleHTTPClientTest { SimpleHTTPClient http = new SimpleHTTPClient(); String url = "https://hl7.org/fhir/us/core/package-list.json?nocache=" + System.currentTimeMillis(); - SimpleHTTPClient.HTTPResult res = http.get(url, "application/json"); + HTTPResult res = http.get(url, "application/json"); // System.out.println(res.getCode()); // System.out.println(new String(res.getContent(), StandardCharsets.UTF_8)); diff --git a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/npm/BasePackageCacheManagerTests.java b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/npm/BasePackageCacheManagerTests.java index f8db6c792..dfb3589ed 100644 --- a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/npm/BasePackageCacheManagerTests.java +++ b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/npm/BasePackageCacheManagerTests.java @@ -9,7 +9,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.hl7.fhir.exceptions.FHIRException; -import org.hl7.fhir.utilities.SimpleHTTPClient; +import org.hl7.fhir.utilities.http.HTTPAuthenticationMode; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -26,7 +26,7 @@ public class BasePackageCacheManagerTests { server.enqueueDummyPackage(); PackageServer testServer = new PackageServer(packageServerUrl) - .withAuthenticationMode(SimpleHTTPClient.AuthenticationMode.BASIC) + .withAuthenticationMode(HTTPAuthenticationMode.BASIC) .withServerType(PackageServer.PackageServerType.NPM) .withUsername(MockPackageServer.DUMMY_USERNAME) .withPassword(MockPackageServer.DUMMY_PASSWORD); @@ -57,11 +57,11 @@ public class BasePackageCacheManagerTests { String packageServerBUrl = serverB.getPackageServerUrl(); PackageServer testServerA = new PackageServer(packageServerAUrl) - .withAuthenticationMode(SimpleHTTPClient.AuthenticationMode.BASIC) + .withAuthenticationMode(HTTPAuthenticationMode.BASIC) .withServerType(PackageServer.PackageServerType.NPM); PackageServer testServerB = new PackageServer(packageServerBUrl) - .withAuthenticationMode(SimpleHTTPClient.AuthenticationMode.BASIC) + .withAuthenticationMode(HTTPAuthenticationMode.BASIC) .withServerType(PackageServer.PackageServerType.NPM); basePackageCacheManager.addPackageServer(testServerA); diff --git a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/npm/PackageServerTest.java b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/npm/PackageServerTest.java index 824900fd8..d9694bc9e 100644 --- a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/npm/PackageServerTest.java +++ b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/npm/PackageServerTest.java @@ -10,7 +10,7 @@ import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.Base64; -import org.hl7.fhir.utilities.SimpleHTTPClient; +import org.hl7.fhir.utilities.http.HTTPAuthenticationMode; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -41,7 +41,7 @@ public class PackageServerTest { server.enqueueDummyPackage(); PackageServer testServer = new PackageServer(packageServerUrl) - .withAuthenticationMode(SimpleHTTPClient.AuthenticationMode.BASIC) + .withAuthenticationMode(HTTPAuthenticationMode.BASIC) .withServerType(PackageServer.PackageServerType.NPM) .withUsername(MockPackageServer.DUMMY_USERNAME) .withPassword(MockPackageServer.DUMMY_PASSWORD); @@ -74,7 +74,7 @@ public class PackageServerTest { server.enqueueDummyPackage(); PackageServer testServer = new PackageServer(packageServerUrl) - .withAuthenticationMode(SimpleHTTPClient.AuthenticationMode.TOKEN) + .withAuthenticationMode(HTTPAuthenticationMode.TOKEN) .withServerType(PackageServer.PackageServerType.NPM) .withToken(MockPackageServer.DUMMY_TOKEN); PackageClient packageClient = new PackageClient(testServer); diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/IgLoader.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/IgLoader.java index 36fc1e218..aadf0b80f 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/IgLoader.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/IgLoader.java @@ -32,12 +32,12 @@ import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.utils.structuremap.StructureMapUtilities; import org.hl7.fhir.utilities.ByteProvider; import org.hl7.fhir.utilities.IniFile; -import org.hl7.fhir.utilities.SimpleHTTPClient; -import org.hl7.fhir.utilities.SimpleHTTPClient.HTTPResult; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.filesystem.ManagedFileAccess; +import org.hl7.fhir.utilities.http.HTTPResult; +import org.hl7.fhir.utilities.http.ManagedWebAccess; import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; import org.hl7.fhir.utilities.npm.NpmPackage; import org.hl7.fhir.utilities.turtle.Turtle; @@ -416,8 +416,7 @@ public class IgLoader implements IValidationEngineLoader { private InputStream fetchFromUrlSpecific(String source, boolean optional) throws FHIRException, IOException { try { - SimpleHTTPClient http = new SimpleHTTPClient(); - HTTPResult res = http.get(source + "?nocache=" + System.currentTimeMillis()); + HTTPResult res = ManagedWebAccess.get(source + "?nocache=" + System.currentTimeMillis()); res.checkThrowException(); return new ByteArrayInputStream(res.getContent()); } catch (IOException e) { @@ -561,14 +560,13 @@ public class IgLoader implements IValidationEngineLoader { private byte[] fetchFromUrlSpecific(String source, String contentType, boolean optional, List errors) throws FHIRException, IOException { try { - SimpleHTTPClient http = new SimpleHTTPClient(); try { // try with cache-busting option and then try withhout in case the server doesn't support that - HTTPResult res = http.get(source + "?nocache=" + System.currentTimeMillis(), contentType); + HTTPResult res = ManagedWebAccess.get(source + "?nocache=" + System.currentTimeMillis(), contentType); res.checkThrowException(); return res.getContent(); } catch (Exception e) { - HTTPResult res = http.get(source, contentType); + HTTPResult res = ManagedWebAccess.get(source, contentType); res.checkThrowException(); return res.getContent(); } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Scanner.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Scanner.java index eec3e31bc..5dd66f704 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Scanner.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/Scanner.java @@ -31,11 +31,11 @@ import org.hl7.fhir.r5.renderers.RendererFactory; import org.hl7.fhir.r5.renderers.utils.RenderingContext; import org.hl7.fhir.r5.renderers.utils.RenderingContext.GenerationRules; import org.hl7.fhir.r5.utils.EOperationOutcome; -import org.hl7.fhir.utilities.SimpleHTTPClient; -import org.hl7.fhir.utilities.SimpleHTTPClient.HTTPResult; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.filesystem.ManagedFileAccess; +import org.hl7.fhir.utilities.http.HTTPResult; +import org.hl7.fhir.utilities.http.ManagedWebAccess; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.xhtml.XhtmlComposer; import org.hl7.fhir.validation.ValidatorUtils.SourceFile; @@ -318,8 +318,7 @@ public class Scanner { } protected void download(String address, String filename) throws IOException { - SimpleHTTPClient http = new SimpleHTTPClient(); - HTTPResult res = http.get(address); + HTTPResult res = ManagedWebAccess.get(address); res.checkThrowException(); TextFile.bytesToFile(res.getContent(), filename); } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java index 29df53882..895bbd2b2 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java @@ -82,13 +82,13 @@ import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy; import org.hl7.fhir.utilities.FhirPublication; import org.hl7.fhir.utilities.IniFile; import org.hl7.fhir.utilities.SIDUtilities; -import org.hl7.fhir.utilities.SimpleHTTPClient; -import org.hl7.fhir.utilities.SimpleHTTPClient.HTTPResult; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.TimeTracker; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.filesystem.ManagedFileAccess; +import org.hl7.fhir.utilities.http.HTTPResult; +import org.hl7.fhir.utilities.http.ManagedWebAccess; import org.hl7.fhir.utilities.npm.CommonPackages; import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; import org.hl7.fhir.utilities.npm.NpmPackage; @@ -915,8 +915,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP if (output.startsWith("http://")) { ByteArrayOutputStream bs = new ByteArrayOutputStream(); handleOutputToStream(r, output, bs, version); - SimpleHTTPClient http = new SimpleHTTPClient(); - HTTPResult res = http.post(output, "application/fhir+xml", bs.toByteArray(), "application/fhir+xml"); + HTTPResult res = ManagedWebAccess.post(output, bs.toByteArray(), "application/fhir+xml", "application/fhir+xml"); res.checkThrowException(); } else { FileOutputStream s = ManagedFileAccess.outStream(output); @@ -1073,8 +1072,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP @Override public byte[] fetchRaw(IResourceValidator validator, String source) throws IOException { - SimpleHTTPClient http = new SimpleHTTPClient(); - HTTPResult res = http.get(source); + HTTPResult res = ManagedWebAccess.get(source); res.checkThrowException(); return res.getContent(); } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/ProfileLoader.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/ProfileLoader.java index 36ce2b154..b73684eb6 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/ProfileLoader.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/ProfileLoader.java @@ -4,11 +4,11 @@ import java.io.File; import java.io.IOException; import org.hl7.fhir.exceptions.FHIRException; -import org.hl7.fhir.utilities.SimpleHTTPClient; -import org.hl7.fhir.utilities.SimpleHTTPClient.HTTPResult; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.filesystem.ManagedFileAccess; +import org.hl7.fhir.utilities.http.HTTPResult; +import org.hl7.fhir.utilities.http.ManagedWebAccess; public class ProfileLoader { public static byte[] loadProfileSource(String src) throws FHIRException, IOException { @@ -25,8 +25,7 @@ public class ProfileLoader { private static byte[] loadProfileFromUrl(String src) throws FHIRException { try { - SimpleHTTPClient http = new SimpleHTTPClient(); - HTTPResult res = http.get(src + "?nocache=" + System.currentTimeMillis()); + HTTPResult res = ManagedWebAccess.get(src + "?nocache=" + System.currentTimeMillis()); res.checkThrowException(); return res.getContent(); } catch (Exception e) { diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ipa/IPAValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ipa/IPAValidator.java index a4f366331..327567cc0 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ipa/IPAValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ipa/IPAValidator.java @@ -7,8 +7,8 @@ import java.util.Map; import org.hl7.fhir.r5.elementmodel.Element; import org.hl7.fhir.r5.elementmodel.JsonParser; -import org.hl7.fhir.utilities.SimpleHTTPClient; -import org.hl7.fhir.utilities.SimpleHTTPClient.HTTPResult; +import org.hl7.fhir.utilities.http.HTTPResult; +import org.hl7.fhir.utilities.http.ManagedWebAccess; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; @@ -160,8 +160,7 @@ public class IPAValidator { private Element makeRequest(ValidationNode vn, String url) { try { - SimpleHTTPClient http = new SimpleHTTPClient(); - HTTPResult result = http.get(url, "application/fhir+json"); + HTTPResult result = ManagedWebAccess.get(url, "application/fhir+json"); if (result.getCode() >= 300) { vn.getIssues().add(new ValidationMessage(Source.IPAValidator, IssueType.EXCEPTION, "http.request", "HTTP Return code is "+result.getCode()+" "+result.getMessage(), diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTests.java index 825ea6243..ded31ec63 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTests.java @@ -70,12 +70,12 @@ import org.hl7.fhir.r5.utils.validation.constants.CodedContentValidationPolicy; import org.hl7.fhir.r5.utils.validation.constants.ContainedReferenceValidationPolicy; import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy; import org.hl7.fhir.utilities.FhirPublication; -import org.hl7.fhir.utilities.SimpleHTTPClient; -import org.hl7.fhir.utilities.SimpleHTTPClient.HTTPResult; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.filesystem.ManagedFileAccess; +import org.hl7.fhir.utilities.http.HTTPResult; +import org.hl7.fhir.utilities.http.ManagedWebAccess; import org.hl7.fhir.utilities.json.JsonException; import org.hl7.fhir.utilities.json.JsonTrackingParser; import org.hl7.fhir.utilities.json.JsonUtilities; @@ -828,8 +828,7 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe @Override public byte[] fetchRaw(IResourceValidator validator, String source) throws MalformedURLException, IOException { - SimpleHTTPClient http = new SimpleHTTPClient(); - HTTPResult res = http.get(source); + HTTPResult res = ManagedWebAccess.get(source); res.checkThrowException(); return res.getContent(); } diff --git a/security.md b/security.md index b277a6740..68a08fd8b 100644 --- a/security.md +++ b/security.md @@ -21,8 +21,19 @@ restricting path access to particular directories. # Network access The library will access the web to download needed collateral, or to access terminology resources or servers. -All access is by http(s) using the Apache... library, and is controlled by the class XXXX where you can -turn all network access off. +All access is by http(s) using base java http library, and is controlled by the class ManagedWebAccess. You can +set the static features of this class to completely cut the library off from the +web, or provide your own web accessor, or limit the web resources accessed +to particular domains or sub-domains. See ManagedWebAccess for details. + +Note that for legacy reasons, network access can also be prohibited using +FhirSettings.setProhibitNetworkAccess(), but this is deprecated. + +Note that libraries that this library depends on may still access the network directly. Review +of the use of these libraries is ongoing. + +Validator: The validator CLI accesses the web to download packages and make use of the +terminology server, which defaults to https://tx.fhir.org. # Logging