Bug 518093 - Unable to deploy via web interface when file's path is part of the file name
diff --git a/org.eclipse.virgo.management.console/src/main/java/org/eclipse/virgo/management/console/UploadServlet.java b/org.eclipse.virgo.management.console/src/main/java/org/eclipse/virgo/management/console/UploadServlet.java index eacbce0..3be4788 100644 --- a/org.eclipse.virgo.management.console/src/main/java/org/eclipse/virgo/management/console/UploadServlet.java +++ b/org.eclipse.virgo.management.console/src/main/java/org/eclipse/virgo/management/console/UploadServlet.java
@@ -10,13 +10,13 @@ *******************************************************************************/ package org.eclipse.virgo.management.console; -import java.io.File; -import java.io.IOException; -import java.io.PrintWriter; -import java.lang.management.ManagementFactory; -import java.net.URI; -import java.util.ArrayList; -import java.util.List; +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.FileItemFactory; +import org.apache.commons.fileupload.disk.DiskFileItemFactory; +import org.apache.commons.fileupload.servlet.ServletFileUpload; +import org.osgi.framework.BundleContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; @@ -27,136 +27,152 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.fileupload.FileItem; -import org.apache.commons.fileupload.FileItemFactory; -import org.apache.commons.fileupload.disk.DiskFileItemFactory; -import org.apache.commons.fileupload.servlet.ServletFileUpload; -import org.osgi.framework.BundleContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.lang.management.ManagementFactory; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; /** - * + * * */ public class UploadServlet extends HttpServlet { - private static final String[] DEPLOYMENT_IDENTITY_FIELDS = new String[]{"type", "symbolicName", "version"}; + private static final String[] DEPLOYMENT_IDENTITY_FIELDS = new String[]{"type", "symbolicName", "version"}; - private static final int HTTP_RESPONSE_INTERNAL_SERVER_ERROR = 500; + private static final int HTTP_RESPONSE_INTERNAL_SERVER_ERROR = 500; private static final String ORG_ECLIPSE_VIRGO_KERNEL_HOME = "org.eclipse.virgo.kernel.home"; - + private static final String DEPLOYER_MBEAN_NAME = "org.eclipse.virgo.kernel:category=Control,type=Deployer"; - - private static final long serialVersionUID = 1L; - - private static final String STAGING_DIR = "/work/org.eclipse.virgo.apps.admin.web.UploadServlet"; - - private static final Logger log = LoggerFactory.getLogger(UploadServlet.class); - private MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer(); - - private String serverHome = null; - - private BundleContext bundleContext = null; + private static final long serialVersionUID = 1L; - public UploadServlet() { - } - - public UploadServlet(BundleContext bundleContext) { - this.bundleContext = bundleContext; - } + private static final String STAGING_DIR = "/work/org.eclipse.virgo.apps.admin.web.UploadServlet"; - /** - * Do not use this method with the HTTPService unless the BundleContext has already been set. - */ - public void init(ServletConfig config) throws ServletException { - super.init(config); - if(bundleContext == null){ - this.bundleContext = (BundleContext) config.getServletContext().getAttribute("osgi-bundlecontext"); - } - this.serverHome = this.bundleContext.getProperty(ORG_ECLIPSE_VIRGO_KERNEL_HOME); + private static final Logger log = LoggerFactory.getLogger(UploadServlet.class); + + private MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer(); + + private String serverHome = null; + + private BundleContext bundleContext = null; + + public UploadServlet() { } - - protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { - try { - File stagingDir = createStagingDirectory(); - FileItemFactory factory = new DiskFileItemFactory(); - ServletFileUpload upload = new ServletFileUpload(factory); - response.setContentType("text/html"); - List<FileItem> items = (List<FileItem>) upload.parseRequest(request); - List<File> uploadedFiles = new ArrayList<File>(); - for (FileItem fileItem : items) { - File uploadedFile = this.doUpload(fileItem, stagingDir); - if(uploadedFile != null){ - uploadedFiles.add(uploadedFile); - } - } - doDeployment(uploadedFiles, response); - } catch (IllegalArgumentException ea){ - PrintWriter writer = response.getWriter(); - writer.append("<ol id=\"uploadResults\"><li>File name contains '/' or '\\', this is not allowed.</ol>"); - writer.close(); - } catch (Exception e) { - log.error(e.toString()); - response.sendError(HTTP_RESPONSE_INTERNAL_SERVER_ERROR, e.toString()); - } - } - - File doUpload(FileItem fileItem, File stagingDir) throws Exception{ - if (!fileItem.isFormField()) { - String name = fileItem.getName(); - if(name != null && name.length() > 0){ - if(name.contains("\\") || name.contains("/")){ - throw new IllegalArgumentException("Security violation, file name contains '/' or '\\'"); - } - File uploadedFile = new File(stagingDir, name); - fileItem.write(uploadedFile); - log.info(String.format("Uploaded artifact of size (%db) to %s", fileItem.getSize(), uploadedFile.getPath())); - return uploadedFile; - } - } - return null; - } - - private void doDeployment(List<File> uploadedFiles, HttpServletResponse response) throws MalformedObjectNameException, NullPointerException, IOException{ - ObjectName objectName = new ObjectName(DEPLOYER_MBEAN_NAME); - PrintWriter writer = response.getWriter(); + + public UploadServlet(BundleContext bundleContext) { + this.bundleContext = bundleContext; + } + + /** + * Do not use this method with the HTTPService unless the BundleContext has already been set. + */ + public void init(ServletConfig config) throws ServletException { + super.init(config); + if (bundleContext == null) { + this.bundleContext = (BundleContext) config.getServletContext().getAttribute("osgi-bundlecontext"); + } + this.serverHome = this.bundleContext.getProperty(ORG_ECLIPSE_VIRGO_KERNEL_HOME); + } + + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { + try { + File stagingDir = createStagingDirectory(); + FileItemFactory factory = new DiskFileItemFactory(); + ServletFileUpload upload = new ServletFileUpload(factory); + response.setContentType("text/html"); + List<FileItem> items = (List<FileItem>) upload.parseRequest(request); + List<File> uploadedFiles = new ArrayList<File>(); + for (FileItem fileItem : items) { + File uploadedFile = this.doUpload(fileItem, stagingDir); + if (uploadedFile != null) { + uploadedFiles.add(uploadedFile); + } + } + doDeployment(uploadedFiles, response); + } catch (IllegalArgumentException ea) { + PrintWriter writer = response.getWriter(); + writer.append("<ol id=\"uploadResults\"><li>File name contains '/' or '\\', this is not allowed.</ol>"); + writer.close(); + } catch (Exception e) { + log.error(e.toString()); + response.sendError(HTTP_RESPONSE_INTERNAL_SERVER_ERROR, e.toString()); + } + } + + File doUpload(FileItem fileItem, File stagingDir) throws Exception { + if (!fileItem.isFormField()) { + String name = fileItem.getName(); + if (name != null && name.length() > 0) { + if (name.contains("\\") || name.contains("/")) { + name = getFileNameFromPath(name); + } + File uploadedFile = new File(stagingDir, name); + fileItem.write(uploadedFile); + log.info(String.format("Uploaded artifact of size (%db) to %s", fileItem.getSize(), uploadedFile.getPath())); + return uploadedFile; + } + } + return null; + } + + private String getFileNameFromPath(String fileName) { + + String strippedFileName = fileName; + + if (fileName.contains("\\") && fileName.contains("/")) { + throw new IllegalArgumentException("Security violation, file name contains '/' and '\\'"); + } else if (fileName.contains("\\")) { + String[] fileNameParts = fileName.split("\\\\"); + strippedFileName = fileNameParts[fileNameParts.length - 1]; + } else if (fileName.contains("/")) { + String[] fileNameParts = fileName.split("/"); + strippedFileName = fileNameParts[fileNameParts.length - 1]; + } + + return strippedFileName; + } + + private void doDeployment(List<File> uploadedFiles, HttpServletResponse response) throws MalformedObjectNameException, NullPointerException, IOException { + ObjectName objectName = new ObjectName(DEPLOYER_MBEAN_NAME); + PrintWriter writer = response.getWriter(); writer.append("<ol id=\"uploadResults\">"); for (File file : uploadedFiles) { - URI uri = file.toURI(); - try { - Object invoke = this.mBeanServer.invoke(objectName, "deploy", new Object[]{uri.toString()}, new String[]{String.class.getName()}); - writer.append("<li>" + file.getName() + " deployed as " + getDeploymentIdentity(invoke) + "</li>"); - } catch (Exception e) { - writer.append("<li>" + file.getName() + " failed to deploy '" + e.getMessage() + "'</li>"); - } - writer.append("<li />"); - } + URI uri = file.toURI(); + try { + Object invoke = this.mBeanServer.invoke(objectName, "deploy", new Object[]{uri.toString()}, new String[]{String.class.getName()}); + writer.append("<li>" + file.getName() + " deployed as " + getDeploymentIdentity(invoke) + "</li>"); + } catch (Exception e) { + writer.append("<li>" + file.getName() + " failed to deploy '" + e.getMessage() + "'</li>"); + } + writer.append("<li />"); + } writer.append("</ol>"); - writer.close(); - } - - private String getDeploymentIdentity(Object deploymentIdentity) { - StringBuilder builder = new StringBuilder(); - if(deploymentIdentity instanceof CompositeDataSupport){ - CompositeDataSupport deploymentIdentityInstance = (CompositeDataSupport) deploymentIdentity; - Object[] all = deploymentIdentityInstance.getAll(DEPLOYMENT_IDENTITY_FIELDS); - builder.append(all[0]); - builder.append(" - ").append(all[1]); - builder.append(": ").append(all[2]); - } - return builder.toString(); - } + writer.close(); + } + + private String getDeploymentIdentity(Object deploymentIdentity) { + StringBuilder builder = new StringBuilder(); + if (deploymentIdentity instanceof CompositeDataSupport) { + CompositeDataSupport deploymentIdentityInstance = (CompositeDataSupport) deploymentIdentity; + Object[] all = deploymentIdentityInstance.getAll(DEPLOYMENT_IDENTITY_FIELDS); + builder.append(all[0]); + builder.append(" - ").append(all[1]); + builder.append(": ").append(all[2]); + } + return builder.toString(); + } private File createStagingDirectory() throws IOException { File pathReference = new File(String.format("%s%s", this.serverHome, STAGING_DIR)); if (!pathReference.exists()) { - if (!pathReference.mkdirs()) { - throw new IOException("Unable to create directory " + pathReference.getAbsolutePath()); - } + if (!pathReference.mkdirs()) { + throw new IOException("Unable to create directory " + pathReference.getAbsolutePath()); + } } return pathReference.getAbsoluteFile(); }
diff --git a/org.eclipse.virgo.management.console/src/test/java/org/eclipse/virgo/management/console/UploadServletTests.java b/org.eclipse.virgo.management.console/src/test/java/org/eclipse/virgo/management/console/UploadServletTests.java index ca6c9f5..884d821 100644 --- a/org.eclipse.virgo.management.console/src/test/java/org/eclipse/virgo/management/console/UploadServletTests.java +++ b/org.eclipse.virgo.management.console/src/test/java/org/eclipse/virgo/management/console/UploadServletTests.java
@@ -10,43 +10,68 @@ *******************************************************************************/ package org.eclipse.virgo.management.console; -import static org.junit.Assert.assertNotNull; - -import java.io.File; -import java.io.IOException; - import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.disk.DiskFileItem; import org.junit.Test; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; +import java.io.File; +import java.io.IOException; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + public class UploadServletTests { - @Test - public void testDoPost() throws IOException { - UploadServlet uploadServlet = new UploadServlet(); - MockHttpServletRequest request = new MockHttpServletRequest("POST", null); - uploadServlet.doPost(request, new MockHttpServletResponse()); - } - - @Test(expected=RuntimeException.class) - public void testDoUploadFail() throws Exception { - UploadServlet uploadServlet = new UploadServlet(); - FileItem fileItem = new DiskFileItem("foo", "json/application", false, "src/test/resources/test.upload", 500, new File("build")); - File stagingDir = new File("build"); - fileItem.getOutputStream(); - uploadServlet.doUpload(fileItem, stagingDir); - } - - @Test - public void testDoUpload() throws Exception { - UploadServlet uploadServlet = new UploadServlet(); - FileItem fileItem = new DiskFileItem("foo", "json/application", false, "test.upload", 500, new File("build")); - File stagingDir = new File("src/test/resources"); - fileItem.getOutputStream(); - File doUpload = uploadServlet.doUpload(fileItem, stagingDir); - assertNotNull(doUpload); - } + @Test + public void testDoPost() throws IOException { + UploadServlet uploadServlet = new UploadServlet(); + MockHttpServletRequest request = new MockHttpServletRequest("POST", null); + uploadServlet.doPost(request, new MockHttpServletResponse()); + } + @Test(expected = RuntimeException.class) + public void testDoUploadFail() throws Exception { + UploadServlet uploadServlet = new UploadServlet(); + FileItem fileItem = new DiskFileItem("foo", "json/application", false, "src/test/resources\\test.upload", 500, new File("build")); + File stagingDir = new File("build"); + fileItem.getOutputStream(); + uploadServlet.doUpload(fileItem, stagingDir); + } + + @Test + public void testDoUpload() throws Exception { + UploadServlet uploadServlet = new UploadServlet(); + FileItem fileItem = new DiskFileItem("foo", "json/application", false, "test.upload", 500, new File("build")); + File stagingDir = new File("src/test/resources"); + fileItem.getOutputStream(); + File doUpload = uploadServlet.doUpload(fileItem, stagingDir); + assertNotNull(doUpload); + assertTrue("test.upload".equals(doUpload.getName())); + } + + @Test + public void testDoUploadWithFullPathUnix() throws Exception { + UploadServlet uploadServlet = new UploadServlet(); + FileItem fileItem = new DiskFileItem("foo", "json/application", false, "src/test/resources/test.upload", 500, new File("build")); + File stagingDir = new File("src/test/resources"); + fileItem.getOutputStream(); + File doUpload = uploadServlet.doUpload(fileItem, stagingDir); + System.out.println(doUpload.getName()); + assertNotNull(doUpload); + assertTrue("test.upload".equals(doUpload.getName())); + } + + + @Test + public void testDoUploadWithFullPathWin() throws Exception { + UploadServlet uploadServlet = new UploadServlet(); + FileItem fileItem = new DiskFileItem("foo", "json/application", false, "src\\test\\resources\\test.upload", 500, new File("build")); + File stagingDir = new File("src/test/resources"); + fileItem.getOutputStream(); + File doUpload = uploadServlet.doUpload(fileItem, stagingDir); + assertNotNull(doUpload); + assertTrue("test.upload".equals(doUpload.getName())); + } }