//////////////////////////////////////////////////////////////////////// // // 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 java.util.Arrays; import javax.servlet.http.HttpServletRequest; import org.json.JSONObject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.SessionAttributes; import org.springframework.web.bind.support.SessionStatus; import com.denimgroup.threadfix.data.entities.Application; import com.denimgroup.threadfix.data.entities.DefectTracker; import com.denimgroup.threadfix.data.entities.Finding; import com.denimgroup.threadfix.data.entities.Permission; import com.denimgroup.threadfix.data.entities.Waf; import com.denimgroup.threadfix.service.ApplicationCriticalityService; import com.denimgroup.threadfix.service.ApplicationService; import com.denimgroup.threadfix.service.DefectTrackerService; import com.denimgroup.threadfix.service.FindingService; import com.denimgroup.threadfix.service.OrganizationService; import com.denimgroup.threadfix.service.PermissionService; import com.denimgroup.threadfix.service.SanitizedLogger; import com.denimgroup.threadfix.service.WafService; import com.denimgroup.threadfix.service.defects.AbstractDefectTracker; import com.denimgroup.threadfix.service.defects.DefectTrackerFactory; import com.denimgroup.threadfix.service.defects.ProjectMetadata; import com.denimgroup.threadfix.webapp.validator.BeanValidator; import com.denimgroup.threadfix.webapp.viewmodels.DefectViewModel; import com.denimgroup.threadfix.webapp.viewmodels.VulnerabilityCollectionModel; @Controller @RequestMapping("/organizations/{orgId}/applications") @SessionAttributes({"defectTracker", "application", "waf", "defectViewModel"}) public class ApplicationsController { public ApplicationsController(){} private final SanitizedLogger log = new SanitizedLogger(ApplicationsController.class); private FindingService findingService; private ApplicationCriticalityService applicationCriticalityService; private ApplicationService applicationService; private DefectTrackerService defectTrackerService; private WafService wafService; private PermissionService permissionService; private OrganizationService organizationService; @Autowired public ApplicationsController(ApplicationService applicationService, FindingService findingService, ApplicationCriticalityService applicationCriticalityService, WafService wafService, DefectTrackerService defectTrackerService, PermissionService permissionService, OrganizationService organizationService) { this.wafService = wafService; this.applicationService = applicationService; this.defectTrackerService = defectTrackerService; this.permissionService = permissionService; this.findingService = findingService; this.applicationCriticalityService = applicationCriticalityService; this.organizationService = organizationService; } @InitBinder public void initBinder(WebDataBinder dataBinder) { dataBinder.setValidator(new BeanValidator()); } @RequestMapping("/{appId}") public String detail(@PathVariable("orgId") Integer orgId, @PathVariable("appId") Integer appId, Model model, HttpServletRequest request) { if (!permissionService.isAuthorized(Permission.READ_ACCESS, orgId, appId)) { return "403"; } Application application = applicationService.loadApplication(appId); if (application == null || !application.isActive()) { log.warn(ResourceNotFoundException.getLogMessage("Application", appId)); throw new ResourceNotFoundException(); } Object successMessage = ControllerUtils.getSuccessMessage(request); Object error = ControllerUtils.getErrorMessage(request); TableSortBean falsePositiveBean = new TableSortBean(); falsePositiveBean.setFalsePositive(true); long numVulns = applicationService.getVulnCount(appId, true); long numClosedVulns = applicationService.getVulnCount(appId, false); long falsePositiveCount = applicationService.getCount(appId, falsePositiveBean); permissionService.addPermissions(model, orgId, appId, Permission.CAN_MANAGE_APPLICATIONS, Permission.CAN_UPLOAD_SCANS, Permission.CAN_MODIFY_VULNERABILITIES, Permission.CAN_SUBMIT_DEFECTS, Permission.CAN_VIEW_JOB_STATUSES, Permission.CAN_GENERATE_REPORTS, Permission.CAN_MANAGE_DEFECT_TRACKERS); if (application.getPassword() != null && !"".equals(application.getPassword())) { application.setPassword(Application.TEMP_PASSWORD); } Object checkForRefresh = ControllerUtils.getItem(request, "checkForRefresh"); Object numScansBeforeUpload = ControllerUtils.getItem(request, "numScansBeforeUpload"); model.addAttribute("numScansBeforeUpload", numScansBeforeUpload); model.addAttribute("checkForRefresh", checkForRefresh); model.addAttribute("applicationCriticalityList", applicationCriticalityService.loadAll()); model.addAttribute("dynamicPathList", findingService.getRecentDynamicPaths(appId)); model.addAttribute("staticPathList", findingService.getRecentStaticPaths(appId)); model.addAttribute("dynamicChannelVulnerabilityList", findingService.getRecentDynamicVulnTypes(appId)); model.addAttribute("staticChannelVulnerabilityList", findingService.getRecentStaticVulnTypes(appId)); model.addAttribute("manualSeverities", findingService.getManualSeverities()); model.addAttribute("numVulns", numVulns); model.addAttribute("defectTrackerList", defectTrackerService.loadAllDefectTrackers()); model.addAttribute("defectTrackerTypeList", defectTrackerService.loadAllDefectTrackerTypes()); model.addAttribute("defectTracker", new DefectTracker()); model.addAttribute("waf", new Waf()); model.addAttribute("createWafUrl", "wafs/new/ajax/appPage"); model.addAttribute("newWaf", new Waf()); model.addAttribute("wafList", wafService.loadAll()); model.addAttribute("wafTypeList", wafService.loadAllWafTypes()); model.addAttribute("numClosedVulns", numClosedVulns); model.addAttribute(new VulnerabilityCollectionModel()); model.addAttribute("successMessage", successMessage); model.addAttribute("errorMessage", error); model.addAttribute(application); model.addAttribute("falsePositiveCount", falsePositiveCount); model.addAttribute("finding", new Finding()); model.addAttribute(new DefectViewModel()); model.addAttribute("teamList", organizationService.loadAllActive()); return "applications/detail"; } // TODO move this to a different spot so as to be less annoying private void addDefectModelAttributes(Model model, int appId, int orgId) { if (!permissionService.isAuthorized(Permission.CAN_SUBMIT_DEFECTS, orgId, appId)) { return; } Application application = applicationService.loadApplication(appId); if (application == null || !application.isActive()) { log.warn(ResourceNotFoundException.getLogMessage("Application", appId)); throw new ResourceNotFoundException(); } if (application.getDefectTracker() == null || application.getDefectTracker().getDefectTrackerType() == null) { return; } applicationService.decryptCredentials(application); AbstractDefectTracker dt = DefectTrackerFactory.getTracker(application); ProjectMetadata data = null; if (dt != null) { data = dt.getProjectMetadata(); } model.addAttribute("defectTrackerName", application.getDefectTracker().getDefectTrackerType().getName()); model.addAttribute("projectMetadata", data); model.addAttribute(new DefectViewModel()); } @RequestMapping("/{appId}/defectSubmission") public String getDefectSubmissionForm(@PathVariable("orgId") int orgId, @PathVariable("appId") int appId, SessionStatus status, Model model) { addDefectModelAttributes(model, appId, orgId); model.addAttribute("contentPage", "defects/submitDefectForm.jsp"); return "ajaxSuccessHarness"; } @PreAuthorize("hasRole('ROLE_CAN_MANAGE_APPLICATIONS')") @RequestMapping("/{appId}/delete") public String processLinkDelete(@PathVariable("orgId") int orgId, @PathVariable("appId") int appId, SessionStatus status) { if (!permissionService.isAuthorized(Permission.READ_ACCESS, orgId, appId)) { return "403"; } Application application = applicationService.loadApplication(appId); if (application != null && application.isActive()) { applicationService.deactivateApplication(application); status.setComplete(); } else { log.warn(ResourceNotFoundException.getLogMessage("Application", appId)); throw new ResourceNotFoundException(); } return "redirect:/organizations/" + String.valueOf(orgId); } // TODO move this elsewhere? @RequestMapping(value = "/jsontest", method = RequestMethod.POST) public @ResponseBody String readJson(@RequestBody DefectTrackerBean bean) { DefectTracker defectTracker = defectTrackerService.loadDefectTracker(bean .getDefectTrackerId()); AbstractDefectTracker dt = DefectTrackerFactory.getTrackerByType(defectTracker, bean.getUserName(), bean.getPassword()); if (dt == null) { log.warn("Incorrect Defect Tracker credentials submitted."); return "Authentication failed"; } String result = dt.getProductNames(); if (result == null || result.equals("Authentication failed")) { return "{ \"message\" : \"Authentication failed\", " + "\"error\" : " + JSONObject.quote(dt.getLastError()) + "}"; } return "{ \"message\" : \"Authentication success\", " + "\"names\" : " + JSONObject.quote(productSort(result)) + "}"; } private String productSort(String products) { if (products == null) { return "Authentication failed"; } String[] splitArray = products.split(",", 0); if (splitArray.length == 0) { return "Authentication failed"; } Arrays.sort(splitArray, String.CASE_INSENSITIVE_ORDER); StringBuilder result = new StringBuilder(); for (String product : splitArray) { if (product != null && !product.trim().equals("")) { result.append(',').append(product); } } return result.substring(1); } }