//////////////////////////////////////////////////////////////////////// // // 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.Calendar; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.ui.ModelMap; 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 com.denimgroup.threadfix.data.entities.Application; import com.denimgroup.threadfix.data.entities.Finding; import com.denimgroup.threadfix.data.entities.Permission; import com.denimgroup.threadfix.data.entities.SurfaceLocation; import com.denimgroup.threadfix.data.entities.Vulnerability; import com.denimgroup.threadfix.data.entities.VulnerabilityComment; import com.denimgroup.threadfix.service.ApplicationService; import com.denimgroup.threadfix.service.PermissionService; import com.denimgroup.threadfix.service.SanitizedLogger; import com.denimgroup.threadfix.service.VulnerabilityCommentService; import com.denimgroup.threadfix.service.VulnerabilityService; @Controller @RequestMapping("/organizations/{orgId}/applications/{appId}/vulnerabilities") public class VulnerabilityController { private VulnerabilityService vulnerabilityService; private ApplicationService applicationService; private VulnerabilityCommentService vulnerabilityCommentService; private PermissionService permissionService; private final SanitizedLogger log = new SanitizedLogger(VulnerabilityController.class); @Autowired public VulnerabilityController(PermissionService permissionService, ApplicationService applicationService, VulnerabilityService vulnerabilityService, VulnerabilityCommentService vulnerabilityCommentService) { this.vulnerabilityService = vulnerabilityService; this.vulnerabilityCommentService = vulnerabilityCommentService; this.permissionService = permissionService; this.applicationService = applicationService; } public VulnerabilityController(){} // switched to not show our guess as to static surfaceLocations - only show // surfaceLocation for dynamic scans. @RequestMapping(value = "/{vulnerabilityId}", method = RequestMethod.GET) public String detail(@PathVariable("appId") int appId, @PathVariable("orgId") int orgId, @PathVariable("vulnerabilityId") int vulnerabilityId, Model model) { if (!permissionService.isAuthorized(Permission.READ_ACCESS,orgId,appId)) { return "403"; } Vulnerability vulnerability = vulnerabilityService.loadVulnerability(vulnerabilityId); checkResourceNotFound(vulnerability, vulnerabilityId, appId); String[] times = vulnerabilityService.getTimeDifferences(vulnerability); SurfaceLocation surfaceLocation = vulnerabilityService .getSurfaceLocationFromDynamicFinding(vulnerability); List<Finding> staticFindingList = vulnerabilityService.getStaticFindings(vulnerability); // if there's only one static finding, display its data flow elements. Finding singleStaticFinding = null; if (staticFindingList != null && staticFindingList.size() == 1) { singleStaticFinding = staticFindingList.get(0); staticFindingList = null; } permissionService.addPermissions(model, orgId, appId, Permission.CAN_MODIFY_VULNERABILITIES); List<VulnerabilityComment> comments = vulnerabilityCommentService.loadAllForVuln(vulnerabilityId); model.addAttribute("singleStaticFinding", singleStaticFinding); model.addAttribute("comments", comments); model.addAttribute("staticFindingList", staticFindingList); model.addAttribute("surfaceLocation", surfaceLocation); model.addAttribute("vulnerability", vulnerability); model.addAttribute("timeArray", times); return "applications/vulnerability"; } // switched to not show our guess as to static surfaceLocations - only show // surfaceLocation for dynamic scans. @RequestMapping(value = "/{vulnerabilityId}/addComment", method = RequestMethod.POST) public String addComment(@PathVariable("appId") int appId, @PathVariable("orgId") int orgId, @RequestParam("comments") String comments, Model model, @PathVariable("vulnerabilityId") int vulnerabilityId) { Vulnerability vulnerability = vulnerabilityService.loadVulnerability(vulnerabilityId); checkResourceNotFound(vulnerability, vulnerabilityId, appId); String result = vulnerabilityCommentService.addCommentToVuln(comments, vulnerabilityId); if (result == null) result = "The submitted comment was invalid."; model.addAttribute("vulnerability", vulnerability); if (!result.equals(VulnerabilityCommentService.VALID)) { model.addAttribute("commentError", result); model.addAttribute("contentPage", "applications/forms/vulnCommentForm.jsp"); return "ajaxFailureHarness"; } List<VulnerabilityComment> commentList = vulnerabilityCommentService.loadAllForVuln(vulnerabilityId); model.addAttribute("comments", commentList); model.addAttribute("contentPage", "applications/vulnComments.jsp"); return "ajaxSuccessHarness"; } @RequestMapping(value = "/{vulnerabilityId}/defect", method = RequestMethod.GET) public String viewDefect(@PathVariable("appId") int appId, @PathVariable("orgId") int orgId, @PathVariable("vulnerabilityId") int vulnerabilityId, ModelMap model) { if (!permissionService.isAuthorized(Permission.READ_ACCESS,orgId,appId)) { return "403"; } Vulnerability vulnerability = vulnerabilityService.loadVulnerability(vulnerabilityId); checkResourceNotFound(vulnerability, vulnerabilityId, appId); if (vulnerability.getDefect() == null) { log.warn("The requested Vulnerability did not have an associated Defect, returning to the Vulnerability page."); return "redirect:/organizations/" + orgId + "/applications/" + appId + "/vulnerabilities/" + vulnerabilityId; } model.addAttribute("defect", vulnerability.getDefect()); return "applications/defects"; } @RequestMapping(value = "/{vulnerabilityId}/close", method = RequestMethod.GET) public String closeVulnerability(@PathVariable("vulnerabilityId") int vulnerabilityId, @PathVariable("appId") int appId, @PathVariable("orgId") int orgId, ModelMap model) { if (!permissionService.isAuthorized(Permission.CAN_MODIFY_VULNERABILITIES, orgId, appId)) { return "403"; } Vulnerability vulnerability = vulnerabilityService.loadVulnerability(vulnerabilityId); checkResourceNotFound(vulnerability, vulnerabilityId, appId); vulnerability.closeVulnerability(null, Calendar.getInstance()); vulnerability.setFoundByScanner(false); vulnerabilityService.storeVulnerability(vulnerability); return "redirect:/organizations/" + orgId + "/applications/" + appId + "/vulnerabilities/" + vulnerabilityId; } @RequestMapping(value = "/{vulnerabilityId}/open", method = RequestMethod.GET) public String openVulnerability(@PathVariable("vulnerabilityId") int vulnerabilityId, @PathVariable("appId") int appId, @PathVariable("orgId") int orgId, ModelMap model) { if (!permissionService.isAuthorized(Permission.CAN_MODIFY_VULNERABILITIES, orgId, appId)) { return "403"; } Vulnerability vulnerability = vulnerabilityService.loadVulnerability(vulnerabilityId); checkResourceNotFound(vulnerability, vulnerabilityId, appId); vulnerability.setActive(true); vulnerabilityService.storeVulnerability(vulnerability); return "redirect:/organizations/" + orgId + "/applications/" + appId + "/vulnerabilities/" + vulnerabilityId; } @RequestMapping(value = "/{vulnerabilityId}/markFalsePositive", method = RequestMethod.GET) public String markFalsePositive(@PathVariable("vulnerabilityId") int vulnerabilityId, @PathVariable("appId") int appId, @PathVariable("orgId") int orgId, ModelMap model) { if (!permissionService.isAuthorized(Permission.CAN_MODIFY_VULNERABILITIES, orgId, appId)) { return "403"; } Vulnerability vulnerability = vulnerabilityService.loadVulnerability(vulnerabilityId); checkResourceNotFound(vulnerability, vulnerabilityId, appId); vulnerability.setIsFalsePositive(true); vulnerabilityService.storeVulnerability(vulnerability); return "redirect:/organizations/" + orgId + "/applications/" + appId + "/vulnerabilities/" + vulnerabilityId; } @RequestMapping(value = "/{vulnerabilityId}/markNotFalsePositive", method = RequestMethod.GET) public String markNotFalsePositive(@PathVariable("vulnerabilityId") int vulnerabilityId, @PathVariable("appId") int appId, @PathVariable("orgId") int orgId, ModelMap model) { if (!permissionService.isAuthorized(Permission.CAN_MODIFY_VULNERABILITIES, orgId, appId)) { return "403"; } Vulnerability vulnerability = vulnerabilityService.loadVulnerability(vulnerabilityId); checkResourceNotFound(vulnerability, vulnerabilityId, appId); vulnerability.setIsFalsePositive(false); vulnerabilityService.storeVulnerability(vulnerability); return "redirect:/organizations/" + orgId + "/applications/" + appId + "/vulnerabilities/" + vulnerabilityId; } @RequestMapping(value = "/{vulnerabilityId}/mergeFindings", method = RequestMethod.GET) public String mergeFinding(@PathVariable("vulnerabilityId") int vulnerabilityId, ModelMap model, @PathVariable("appId") int appId, @PathVariable("orgId") int orgId) { if (!permissionService.isAuthorized(Permission.CAN_MODIFY_VULNERABILITIES, orgId, appId)) { return "403"; } Vulnerability vulnerability = vulnerabilityService.loadVulnerability(vulnerabilityId); checkResourceNotFound(vulnerability, vulnerabilityId, appId); if (vulnerability.getFindings() != null && vulnerability.getFindings().size() != 0 && vulnerability.getFindings().size() != 1) { List<Finding> findings = vulnerability.getFindings(); model.addAttribute(findings); } model.addAttribute(vulnerability); return "/applications/vulnerability"; } private void checkResourceNotFound(Vulnerability vuln, int vulnId, int appId) { Application application = applicationService.loadApplication(appId); if (vuln == null || application == null || !application.isActive()) { log.warn(ResourceNotFoundException.getLogMessage("Vulnerability", vulnId)); throw new ResourceNotFoundException(); } } }