Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion server/src/com/mirth/connect/server/MirthWebServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,6 @@ public boolean accept(File file) {
servletContextHandler.addFilter(new FilterHolder(new MethodFilter()), "/*", EnumSet.of(DispatcherType.REQUEST));
servletContextHandler.addServlet(new ServletHolder(new WebStartServlet()), "/webstart.jnlp");
servletContextHandler.addServlet(new ServletHolder(new WebStartServlet()), "/webstart");
servletContextHandler.addServlet(new ServletHolder(new WebStartServlet()), "/webstart/extensions/*");
handlers.addHandler(servletContextHandler);

// add the default handler for misc requests (favicon, etc.)
Expand Down
60 changes: 6 additions & 54 deletions server/src/com/mirth/connect/server/servlets/WebStartServlet.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilderFactory;

import com.mirth.connect.client.core.BrandingConstants;
import org.apache.commons.configuration2.PropertiesConfiguration;
import org.apache.commons.configuration2.ex.ConfigurationException;
import org.apache.commons.lang3.StringUtils;
Expand Down Expand Up @@ -85,10 +84,6 @@ public void doGet(HttpServletRequest request, HttpServletResponse response) thro
if ((request.getRequestURI().equals(contextPathProp + "/webstart.jnlp") || request.getRequestURI().equals(contextPathProp + "/webstart")) && isWebstartRequestValid(request)) {
jnlpDocument = getAdministratorJnlp(request);
response.setHeader("Content-Disposition", "attachment; filename = \"webstart.jnlp\"");
} else if (request.getServletPath().equals("/webstart/extensions") && isWebstartExtensionsRequestValid(request, contextPathProp)) {
String extensionPath = getExtensionPath(request);
jnlpDocument = getExtensionJnlp(getExtensionPath(request));
response.setHeader("Content-Disposition", "attachment; filename = \"" + extensionPath + ".jnlp\"");
} else {
response.setContentType("");
}
Expand Down Expand Up @@ -123,16 +118,6 @@ private boolean isWebstartRequestValid(HttpServletRequest request) {
return true;
}

private boolean isWebstartExtensionsRequestValid(HttpServletRequest request, String contextPathProp) {
// Don't allow any parameters and don't allow modified URIs
return request.getParameterMap().isEmpty()
&& (contextPathProp + request.getServletPath() + "/" + getExtensionPath(request)).equals(StringUtils.removeEnd(request.getRequestURI(), ".jnlp"));
}

private String getExtensionPath(HttpServletRequest request) {
return StringUtils.removeEnd(StringUtils.removeStart(request.getPathInfo(), "/"), ".jnlp");
}

protected Document getAdministratorJnlp(HttpServletRequest request) throws Exception {
InputStream clientJnlpIs = null;
Document document;
Expand Down Expand Up @@ -264,9 +249,7 @@ protected Document getAdministratorJnlp(HttpServletRequest request) throws Excep
}

for (String extensionPath : extensionPathsToAddToJnlp) {
Element extensionElement = document.createElement("extension");
extensionElement.setAttribute("href", "webstart/extensions/" + extensionPath + ".jnlp");
resourcesElement.appendChild(extensionElement);
getExtensionJnlp(extensionPath, allExtensions, document, resourcesElement);
}

Element applicationDescElement = (Element) jnlpElement.getElementsByTagName("application-desc").item(0);
Expand Down Expand Up @@ -316,16 +299,13 @@ private boolean doesExtensionHaveClientOrSharedLibraries(MetaData extension) {
return false;
}

protected Document getExtensionJnlp(String extensionPath) throws Exception {
List<MetaData> allExtensions = new ArrayList<MetaData>();
allExtensions.addAll(ControllerFactory.getFactory().createExtensionController().getConnectorMetaData().values());
allExtensions.addAll(ControllerFactory.getFactory().createExtensionController().getPluginMetaData().values());
private void getExtensionJnlp(String extensionPath, List<MetaData> allExtensions, Document document, Element resourcesElement) throws Exception {
Set<String> librariesToAddToJnlp = new HashSet<String>();
List<String> extensionsWithThePath = new ArrayList<String>();
boolean foundExtensionPath = false;

for (MetaData metaData : allExtensions) {
if (metaData.getPath().equals(extensionPath)) {
extensionsWithThePath.add(metaData.getName());
foundExtensionPath = true;

for (ExtensionLibrary library : metaData.getLibraries()) {
if (library.getType().equals(ExtensionLibrary.Type.CLIENT) || library.getType().equals(ExtensionLibrary.Type.SHARED)) {
Expand All @@ -335,47 +315,19 @@ protected Document getExtensionJnlp(String extensionPath) throws Exception {
}
}

if (extensionsWithThePath.isEmpty()) {
if (!foundExtensionPath) {
throw new Exception("Extension metadata could not be located for the path: " + extensionPath);
}

DocumentBuilderFactory dbf = getSecureDocumentBuilderFactory();
Document document = dbf.newDocumentBuilder().newDocument();
Element jnlpElement = document.createElement("jnlp");

Element informationElement = document.createElement("information");

Element titleElement = document.createElement("title");
titleElement.setTextContent("Mirth Connect Extension - [" + StringUtils.join(extensionsWithThePath, ",") + "]");
informationElement.appendChild(titleElement);

Element vendorElement = document.createElement("vendor");
vendorElement.setTextContent(BrandingConstants.COMPANY_NAME);
informationElement.appendChild(vendorElement);

jnlpElement.appendChild(informationElement);

Element securityElement = document.createElement("security");
securityElement.appendChild(document.createElement("all-permissions"));
jnlpElement.appendChild(securityElement);

Element resourcesElement = document.createElement("resources");

File extensionDirectory = new File(ExtensionController.getExtensionsPath() + extensionPath);

for (String library : librariesToAddToJnlp) {
Element jarElement = document.createElement("jar");
jarElement.setAttribute("download", "eager");
// this path is relative to the servlet path
jarElement.setAttribute("href", "libs/" + extensionPath + "/" + library);
jarElement.setAttribute("href", "webstart/extensions/libs/" + extensionPath + "/" + library);
jarElement.setAttribute("sha256", getDigest(extensionDirectory, library));
resourcesElement.appendChild(jarElement);
}

jnlpElement.appendChild(resourcesElement);
jnlpElement.appendChild(document.createElement("component-desc"));
document.appendChild(jnlpElement);
return document;
}

private String getDigest(File directory, String filePath) throws Exception {
Expand Down
103 changes: 2 additions & 101 deletions server/test/com/mirth/connect/server/servlets/WebStartServletTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -203,91 +203,6 @@ public void testDoGetCoreModifiedURL() throws Exception {
assertNull(response.getHeader("Content-Disposition"));
}

@Test
public void testDoGetExtension() throws Exception {
// Test /webstart/extensions/testextension
HttpServletRequest request = mock(HttpServletRequest.class);
when(request.getRequestURI()).thenReturn("/webstart/extensions/testextension");
when(request.getServletPath()).thenReturn("/webstart/extensions");
when(request.getPathInfo()).thenReturn("/testextension");
when(request.getParameterNames()).thenReturn(Collections.emptyEnumeration());

TestHttpServletResponse response = new TestHttpServletResponse();

webStartServlet.doGet(request, response);

assertEquals(normalizeWhitespace(EXTENSION_JNLP), normalizeWhitespace(response.getResponseString()));
assertEquals("application/x-java-jnlp-file", response.getContentType());
assertEquals("no-cache", response.getHeader("Pragma"));
assertEquals("nosniff", response.getHeader("X-Content-Type-Options"));
assertEquals("attachment; filename = \"testextension.jnlp\"", response.getHeader("Content-Disposition"));

// Test /webstart/extensions/testextension.jnlp
request = mock(HttpServletRequest.class);
when(request.getRequestURI()).thenReturn("/webstart/extensions/testextension.jnlp");
when(request.getServletPath()).thenReturn("/webstart/extensions");
when(request.getPathInfo()).thenReturn("/testextension");
when(request.getParameterNames()).thenReturn(Collections.emptyEnumeration());

response = new TestHttpServletResponse();

webStartServlet.doGet(request, response);

assertEquals(normalizeWhitespace(EXTENSION_JNLP), normalizeWhitespace(response.getResponseString()));
assertEquals("application/x-java-jnlp-file", response.getContentType());
assertEquals("no-cache", response.getHeader("Pragma"));
assertEquals("nosniff", response.getHeader("X-Content-Type-Options"));
assertEquals("attachment; filename = \"testextension.jnlp\"", response.getHeader("Content-Disposition"));
}

@Test
public void testDoGetExtensionQueryParams() throws Exception {
HttpServletRequest request = mock(HttpServletRequest.class);
when(request.getRequestURI()).thenReturn("/webstart/extensions/testextension");
when(request.getServletPath()).thenReturn("/webstart/extensions");
when(request.getPathInfo()).thenReturn("/testextension");

Map<String, String[]> parameters = new HashMap<>();
parameters.put("maxHeapSize", new String[] { "1024m" });

when(request.getParameterNames()).thenReturn(Collections.enumeration(parameters.keySet()));
when(request.getParameter(anyString())).thenAnswer(new Answer<String>() {
@Override
public String answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
return parameters.get((String) args[0])[0];
}
});
when(request.getParameterMap()).thenReturn(parameters);

TestHttpServletResponse response = new TestHttpServletResponse();

webStartServlet.doGet(request, response);

assertEquals("", response.getResponseString().trim());
assertEquals("", response.getResponseString().trim());
assertEquals("", response.getContentType());
assertNull(response.getHeader("Content-Disposition"));
}

@Test
public void testDoGetExtensionModifiedURL() throws Exception {
HttpServletRequest request = mock(HttpServletRequest.class);
when(request.getRequestURI()).thenReturn("/webstart/extensions/testextension;rfd.bat");
when(request.getServletPath()).thenReturn("/webstart/extensions");
when(request.getPathInfo()).thenReturn("/testextension");
when(request.getParameterNames()).thenReturn(Collections.emptyEnumeration());

TestHttpServletResponse response = new TestHttpServletResponse();

webStartServlet.doGet(request, response);

assertEquals("", response.getResponseString().trim());
assertEquals("", response.getResponseString().trim());
assertEquals("", response.getContentType());
assertNull(response.getHeader("Content-Disposition"));
}

private static class TestHttpServletResponse implements HttpServletResponse {

private String contentType;
Expand Down Expand Up @@ -521,13 +436,6 @@ protected Document getAdministratorJnlp(HttpServletRequest request) throws Excep
return factory.newDocumentBuilder()
.parse(new ByteArrayInputStream(CORE_JNLP.getBytes()));
}

@Override
protected Document getExtensionJnlp(String extensionPath) throws Exception {
DocumentBuilderFactory factory = getSecureDocumentBuilderFactory();
return factory.newDocumentBuilder()
.parse(new ByteArrayInputStream(EXTENSION_JNLP.getBytes()));
}
}

private static DocumentBuilderFactory getSecureDocumentBuilderFactory() throws Exception {
Expand Down Expand Up @@ -558,16 +466,9 @@ private static String normalizeWhitespace(String input) {
+ " <j2se href=\"http://java.sun.com/products/autodl/j2se\" max-heap-size=\"512m\" version=\"1.6+\"/>\n"
+ " <jar download=\"eager\" href=\"webstart/client-lib/mirth-client.jar\" main=\"true\" sha256=\"0Lv3mOM4e10OBhk78/ST2CzHrXtm+EcZibxV7VfdbI8=\"/>\n"
+ " <jar download=\"eager\" href=\"webstart/client-lib/mirth-client-core.jar\" sha256=\"testsha256\"/>\n"
+ " <extension href=\"webstart/extensions/test.jnlp\"/>\n" + " </resources>\n" + " \n"
+ " <jar download=\"eager\" href=\"webstart/extensions/libs/file/test-client.jar\" sha256=\"testsha256\"/>\n"
+ " <jar download=\"eager\" href=\"webstart/extensions/libs/file/test-shared.jar\" sha256=\"testsha256\"/>\n" + " </resources>\n" + " \n"
+ " <application-desc main-class=\"com.mirth.connect.client.ui.Mirth\">\n"
+ " <argument>https://localhost:8443</argument>\n" + " <argument>4.5.2</argument>\n"
+ " </application-desc>\n" + "</jnlp>";

private static String EXTENSION_JNLP = "<jnlp>\n" + " <information>\n"
+ " <title>Mirth Connect Extension - [Test Writer,Test Reader]</title>\n"
+ " <vendor>NextGen Healthcare</vendor>\n" + " </information>\n" + " <security>\n"
+ " <all-permissions/>\n" + " </security>\n" + " <resources>\n"
+ " <jar download=\"eager\" href=\"libs/file/test-client.jar\" sha256=\"testsha256\"/>\n"
+ " <jar download=\"eager\" href=\"libs/file/test-shared.jar\" sha256=\"testsha256\"/>\n"
+ " </resources>\n" + " <component-desc/>\n" + "</jnlp>\n" + "";
}
Loading