0

In a Spring MVC-based project, Spring's CommonsMultipartFile is used to handle the file upload/transfer process. The overall file uploading process is working fine in Linux if I run the project from STS, but when I export the WAR file from the source, deploy the WAR and run the process it shows, a Permission Denied issue. Here is the sample code that was written to handle the file upload process:

Controller file Code:

@RequestMapping(value = "/jsonBulkUploadRequest", method = RequestMethod.POST)
@ResponseBody
public void uploadBulkFile(BulkUploadEntity remittance) throws Exception {
    bulkUploader.uploadBulkFile(remittance);
}

Service File Code

public void uploadBulkFile(BulkUploadEntity uploadItem) throws Exception {
    CommonsMultipartFile file = uploadItem.getFile();

    fileUploadStatus.put(file.getOriginalFilename().toUpperCase(), "Inprogress");
    //added time as file with same name can be uploaded 
    String fileNameWithDateTime = file.getOriginalFilename().substring(0, file.getOriginalFilename().lastIndexOf(STR_DOT)) + STR_DASH
                + nOFACDateUtils.getCurrentTimeStamp() + file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(STR_DOT));
    File f = new File(fileNameWithDateTime);

    file.transferTo(f); // While inside this method, permission denied error raised

    // process other uploaded file related task
    f.delete();
}

CommonsMultipartFile file of Spring MultipartFile:

@Override
public void transferTo(File dest) throws IOException, IllegalStateException {
    if (!isAvailable()) {
        throw new IllegalStateException("File has already been moved - cannot be transferred again");
    }

    if (dest.exists() && !dest.delete()) {
        throw new IOException("Destination file [" + dest.getAbsolutePath() + "] already exists and could not be deleted");
    }

    try {
        this.fileItem.write(dest);
        if (logger.isDebugEnabled()) {
            String action = "transferred";
            if (!this.fileItem.isInMemory()) {
                action = isAvailable() ? "copied" : "moved";
            }
            logger.debug("Multipart file '" + getName() + "' with original filename [" +
                        getOriginalFilename() + "], stored " + getStorageDescription() + ": " +
                        action + " to [" + dest.getAbsolutePath() + "]");
        }
    }
    catch (FileUploadException ex) {
        throw new IllegalStateException(ex.getMessage());
    }
    catch (IOException ex) {
        throw ex;
    }
    catch (Exception ex) {
        logger.error("Could not transfer to file", ex);
        throw new IOException("Could not transfer to file: " + ex.getMessage());
    }
}

Interestingly there are no logs in catalina.out file, but here is the exception I receive in the browser network tab:

java.io.FileNotFoundException: 08_06_2022-20220906112643.xlsx (Permission denied)
    java.io.FileOutputStream.open0(Native Method)
    java.io.FileOutputStream.open(FileOutputStream.java:270)
    java.io.FileOutputStream.<init>(FileOutputStream.java:213)
    java.io.FileOutputStream.<init>(FileOutputStream.java:162)
    org.apache.commons.fileupload.disk.DiskFileItem.write(DiskFileItem.java:394)
    org.springframework.web.multipart.commons.CommonsMultipartFile.transferTo(CommonsMultipartFile.java:142)
    com.nazdaqTechnologies.nofac.service.BulkUploader.uploadBulkFile(BulkUploader.java:68)
    com.nazdaqTechnologies.nofac.controller.SdnListController.uploadBulkFile(SdnListController.java:777)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    java.lang.reflect.Method.invoke(Method.java:498)
    org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215)
    org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
    org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:781)
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:721)
    org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83)
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
    org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:681)
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    org.apache.catalina.filters.CorsFilter.handleNonCORS(CorsFilter.java:368)
    org.apache.catalina.filters.CorsFilter.doFilter(CorsFilter.java:174)

The above log clearly indicates that the file we are looking for is not found either for permission issue or the file is not there, but my question is why this issue is not raised when I run and debug the source code in Linux?

To raise the issue, I use the same Linux server, the same Tomcat where the WAR files are deployed through RDP, but when I run the source or debug, the file upload process works smoothly. The issue is raised only when I export the source code as WAR and deploy the WAR file in the tomcat and test the file upload. It seems weird to me, and have no idea what is the exact reason and what is the solution.

Hope someone here in StackOverflow can help me to identify and if possible solve the issue.

  • Thanks
Shimul
  • 463
  • 2
  • 7
  • 33
  • 1
    Clearly says *(Permission denied)* – Scary Wombat Jun 09 '22 at 05:45
  • 2
    Because it tries to write a file inside the WAR and that isn't allowed. It works when running from STS because you aren't running from a jar/war and directly on the file system. You need to write to a path on the file system and not the current directory. – M. Deinum Jun 09 '22 at 05:56
  • @M.Deinum Thanks for your comment brother. As you know when a WAR file is pushed inside webapps, it automatically deploys the WAR file and creates a directory. Then why it will try to write inside the WAR, not the directory? Also, all of the related directories and/or paths are configured outside tomcat, so I assume those should be used. **Btw, do you have any suggestions on how can I update the code to fix the issue?** – Shimul Jun 09 '22 at 09:02
  • If it creates a dir or not depends on your config and server. Regardless of that you just cannot write to the classpath (luckily that is else it would be quite an attack vector). I already gave the solution, write to a known directory on the filesystem and not the root of your application (or the current path). – M. Deinum Jun 09 '22 at 09:29

0 Answers0