//////////////////////////////////////////////////////////////////////// // // Copyright (c) 2009-2013 Denim Group, Ltd. // // The contents of this file are subject to the Mozilla Public License // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at // http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the // License for the specific language governing rights and limitations // under the License. // // The Original Code is ThreadFix. // // The Initial Developer of the Original Code is Denim Group, Ltd. // Portions created by Denim Group, Ltd. are Copyright (C) // Denim Group, Ltd. All Rights Reserved. // // Contributor(s): Denim Group, Ltd. // //////////////////////////////////////////////////////////////////////// package com.denimgroup.threadfix.webapp.controller; import javax.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.servlet.ModelAndView; import com.denimgroup.threadfix.data.entities.Application; import com.denimgroup.threadfix.data.entities.ApplicationChannel; import com.denimgroup.threadfix.data.entities.ChannelType; import com.denimgroup.threadfix.data.entities.Permission; import com.denimgroup.threadfix.service.ApplicationChannelService; import com.denimgroup.threadfix.service.ApplicationService; import com.denimgroup.threadfix.service.ChannelTypeService; import com.denimgroup.threadfix.service.PermissionService; import com.denimgroup.threadfix.service.SanitizedLogger; import com.denimgroup.threadfix.service.ScanService; import com.denimgroup.threadfix.service.ScanTypeCalculationService; import com.denimgroup.threadfix.service.channel.ScanImportStatus; @Controller @RequestMapping("/organizations/{orgId}/applications/{appId}/scans/upload") public class UploadScanController { public static final String SCANNER_TYPE_ERROR = "ThreadFix was unable to find a suitable " + "scanner type for the file. Please choose one from the list."; private ScanService scanService; private ScanTypeCalculationService scanTypeCalculationService; private ChannelTypeService channelTypeService; private ApplicationService applicationService; private ApplicationChannelService applicationChannelService; private PermissionService permissionService; private final SanitizedLogger log = new SanitizedLogger(UploadScanController.class); @Autowired public UploadScanController(ScanService scanService, ChannelTypeService channelTypeService, ScanTypeCalculationService scanTypeCalculationService, PermissionService permissionService, ApplicationService applicationService, ApplicationChannelService applicationChannelService) { this.scanService = scanService; this.scanTypeCalculationService = scanTypeCalculationService; this.permissionService = permissionService; this.applicationService = applicationService; this.channelTypeService = channelTypeService; this.applicationChannelService = applicationChannelService; } public UploadScanController(){} @RequestMapping(method = RequestMethod.GET) public ModelAndView uploadIndex(@PathVariable("orgId") int orgId, @PathVariable("appId") int appId) { if (!permissionService.isAuthorized(Permission.CAN_UPLOAD_SCANS, orgId, appId)){ return new ModelAndView("403"); } return index(orgId, appId, null, null); } private ModelAndView index(int orgId, int appId, String message, ChannelType type) { Application application = applicationService.loadApplication(appId); if (application == null) { log.warn(ResourceNotFoundException.getLogMessage("Application", appId)); throw new ResourceNotFoundException(); } ModelAndView mav = new ModelAndView("ajaxFailureHarness"); mav.addObject(application); mav.addObject("message",message); if (message != null && message.equals(SCANNER_TYPE_ERROR)) { mav.addObject("showTypeSelect", true); } mav.addObject("channelTypes",channelTypeService.getChannelTypeOptions(null)); mav.addObject("type",type); mav.addObject("contentPage","applications/forms/uploadScanForm.jsp"); return mav; } // TODO move some of this to the service layer @RequestMapping(method = RequestMethod.POST) public ModelAndView uploadSubmit(@PathVariable("appId") int appId, @PathVariable("orgId") int orgId, HttpServletRequest request, @RequestParam("file") MultipartFile file) { if (!permissionService.isAuthorized(Permission.CAN_UPLOAD_SCANS, orgId, appId)){ return new ModelAndView("403"); } Integer myChannelId = scanTypeCalculationService.calculateScanType(appId, file, request.getParameter("channelId")); if (myChannelId == null) { log.warn("ThreadFix was unable to figure out what scanner type to use."); return index(orgId, appId, SCANNER_TYPE_ERROR, null); } ScanCheckResultBean returnValue = null; String fileName = scanTypeCalculationService.saveFile(myChannelId, file); if (fileName == null || fileName.equals("")) { log.warn("Saving the file to disk did not return a file name. Returning to scan upload page."); return index(orgId, appId, "Unable to save the file to disk.", null); } try { returnValue = scanService.checkFile(myChannelId, fileName); } catch (OutOfMemoryError e) { log.error("OutOfMemoryError thrown while checking file. Logging and re-throwing.", e); ControllerUtils.addErrorMessage(request, "OutOfMemoryError encountered while checking file."); throw e; } Application app = applicationService.loadApplication(appId); if (app == null || !app.isActive()) { log.warn(ResourceNotFoundException.getLogMessage("Application",appId)); throw new ResourceNotFoundException(); } if (returnValue != null && returnValue.getScanCheckResult() != null && ScanImportStatus.SUCCESSFUL_SCAN.equals(returnValue.getScanCheckResult())) { if (app.getScans() == null) { ControllerUtils.addItem(request, "numScansBeforeUpload", 0); } else { ControllerUtils.addItem(request, "numScansBeforeUpload", app.getScans().size()); } scanService.addFileToQueue(myChannelId, fileName, returnValue.getTestDate()); } else if (returnValue != null && returnValue.getScanCheckResult() != null && ScanImportStatus.EMPTY_SCAN_ERROR.equals(returnValue.getScanCheckResult())) { Integer emptyScanId = scanService.saveEmptyScanAndGetId(myChannelId, fileName); ModelAndView confirmPage = new ModelAndView("scans/confirm"); confirmPage.addObject("scanId", emptyScanId); return confirmPage; } else { if (app.getId() != null && app.getOrganization() != null && app.getOrganization().getId() != null) { ChannelType channelType = null; if (returnValue.getScanCheckResult() != null && (returnValue.getScanCheckResult().equals(ScanImportStatus.BADLY_FORMED_XML) || returnValue.getScanCheckResult().equals(ScanImportStatus.WRONG_FORMAT_ERROR) || returnValue.getScanCheckResult().equals(ScanImportStatus.OTHER_ERROR))) { ApplicationChannel appChannel = applicationChannelService.loadApplicationChannel(myChannelId); channelType = appChannel.getChannelType(); } return index(app.getOrganization().getId(), app.getId(), returnValue.getScanCheckResult().toString(), channelType); } else { log.warn("The request included an invalidly configured " + "Application, throwing ResourceNotFoundException."); throw new ResourceNotFoundException(); } } if (app.getOrganization() != null) { ControllerUtils.addSuccessMessage(request, "The scan was successfully submitted for processing. This page will refresh when it finishes."); ControllerUtils.addItem(request, "checkForRefresh", 1); ModelAndView mav = new ModelAndView("ajaxRedirectHarness"); mav.addObject("contentPage","/organizations/" + orgId + "/applications/" + appId); return mav; } else { log.warn("Redirecting to the jobs page because it was impossible to redirect to the Application."); return new ModelAndView("redirect:/jobs/open"); } } @RequestMapping(value = "/{emptyScanId}/confirm", method = RequestMethod.GET) public ModelAndView confirm(@PathVariable("orgId") Integer orgId, @PathVariable("appId") Integer appId, @PathVariable("emptyScanId") Integer emptyScanId, HttpServletRequest request) { if (!permissionService.isAuthorized(Permission.CAN_UPLOAD_SCANS, orgId, appId)){ return new ModelAndView("403"); } scanService.addEmptyScanToQueue(emptyScanId); Application app = applicationService.loadApplication(appId); if (app == null || !app.isActive()) { log.warn(ResourceNotFoundException.getLogMessage("Application",appId)); throw new ResourceNotFoundException(); } if (app.getOrganization() != null && app.getOrganization().getId() != null) { ControllerUtils.addSuccessMessage(request, "The empty scan was successfully added to the queue for processing."); return new ModelAndView("redirect:/organizations/" + app.getOrganization().getId() + "/applications/" + app.getId()); } else { return new ModelAndView("redirect:/jobs/open"); } } @RequestMapping(value = "/{emptyScanId}/cancel", method = RequestMethod.GET) public String cancel(@PathVariable("orgId") Integer orgId, @PathVariable("appId") Integer appId, @PathVariable("emptyScanId") Integer emptyScanId) { if (!permissionService.isAuthorized(Permission.CAN_UPLOAD_SCANS, orgId, appId)){ return "403"; } scanService.deleteEmptyScan(emptyScanId); return "redirect:/organizations/" + orgId + "/applications/" + appId + "/scans/upload"; } }