// This method returns all of the vulnerabilities and tab numbers public Object tableMap(int orgId, int appId, TableSortBean bean) throws IOException { if (appId != -1) { Application application = applicationService.loadApplication(appId); if (application == null || !application.isActive()) { log.warn(ResourceNotFoundException.getLogMessage("Application", appId)); throw new ResourceNotFoundException(); } // we update vulns and application information but not scan vulnerabilityFilterService.updateVulnerabilities(application); } if (orgId != -1) { Organization organization = organizationService.loadById(orgId); if (organization == null || !organization.isActive()) { log.warn(ResourceNotFoundException.getLogMessage("Team", orgId)); throw new ResourceNotFoundException(); } // we update vulns and team information but not scan vulnerabilityFilterService.updateVulnerabilities( organization, organization.getActiveAppIds()); } if (!PermissionUtils.isAuthorized(Permission.READ_ACCESS, orgId, appId)) { return RestResponse.failure("You are not authorized to view this information."); } return RestResponse.success("Bulk Operation successfully ended."); }
@Override public void changeTagInVulnComments() { LOG.info( "About to update all tags in Vulnerability Comments from Application Tag to Comment Tag."); List<VulnerabilityComment> vulnerabilityComments = vulnerabilityCommentDao.retrieveAllActive(); if (vulnerabilityComments == null) { LOG.info("There is no vulnerability comments in the system."); return; } LOG.info( "Looking for tags in " + vulnerabilityComments.size() + " vulnerability comments, and change them if found."); for (VulnerabilityComment comment : vulnerabilityComments) { List<Tag> newTags = CollectionUtils.list(); for (Tag tag : comment.getTags()) { if (tag.getType() == TagType.APPLICATION) { Tag sameTagInComment = loadCommentTag(tag.getName()); if (sameTagInComment != null) newTags.add(sameTagInComment); else LOG.warn( "Can't find comment tag " + tag.getName() + " to change for comment in vulnerability ID " + comment.getVulnerability().getId()); } else newTags.add(tag); } comment.setTags(newTags); vulnerabilityCommentDao.saveOrUpdate(comment); } }
@RequestMapping(value = "/snapshot/scanComparison", method = RequestMethod.POST) public @ResponseBody Object getScanComparison( @ModelAttribute VulnerabilitySearchParameters reportParameters) throws IOException { long start = System.currentTimeMillis(); log.info("Generating Scan Comparison report"); Map<String, Object> result = vulnerabilitySearchService.generateScanComparisonReport(reportParameters); log.info("Scan Comparison report took " + (System.currentTimeMillis() - start) + " ms"); return RestResponse.success(result); }
public static Project getJiraProjectMetadata(String jsonString) { try { return getLenientObjectMapper() .readValue(jsonString, JiraJsonMetadataResponse.class) .getProjectOrNull(); } catch (IOException e) { LOG.info("Failed to deserialize JSON."); LOG.debug("Failing JSON: " + jsonString, e); throw new RestIOException(e, "Unable to parse server response."); } }
@JsonView(AllViews.UIVulnSearch.class) @RequestMapping(value = "/addBatchVulnTagging", method = RequestMethod.POST) public Object addBatchTagging( @PathVariable("orgId") Integer orgId, @PathVariable("appId") Integer appId, @ModelAttribute VulnerabilityCollectionModel vulnerabilityCollectionModel, Model model) throws IOException { if (!PermissionUtils.isAuthorized(Permission.CAN_MODIFY_VULNERABILITIES, orgId, appId)) { return RestResponse.failure("You are not authorized to modify vulnerabilities."); } if (!checkCollectionModel(vulnerabilityCollectionModel, model)) { return RestResponse.failure("Couldn't complete bulk vulnerability operation."); } log.info( "About to tag to " + vulnerabilityCollectionModel.getVulnerabilityIds().size() + " Vulnerabilities."); vulnerabilityService.batchTagging( vulnerabilityCollectionModel.getVulnerabilityIds(), vulnerabilityCollectionModel.getTags()); return RestResponse.success(vulnerabilityCollectionModel.getTags()); }
@JsonView(AllViews.UIVulnSearch.class) @RequestMapping(value = "/addBatchComment", method = RequestMethod.POST) public Object addBatchComment( @PathVariable("orgId") Integer orgId, @PathVariable("appId") Integer appId, @ModelAttribute VulnerabilityCollectionModel vulnerabilityCollectionModel, Model model) throws IOException { if (!PermissionUtils.isAuthorized(Permission.CAN_SUBMIT_COMMENTS, orgId, appId)) { return RestResponse.failure("You are not authorized to modify vulnerabilities."); } if (!checkCollectionModel(vulnerabilityCollectionModel, model)) { return RestResponse.failure("Couldn't complete bulk vulnerability operation."); } log.info( "About to add comment to " + vulnerabilityCollectionModel.getVulnerabilityIds().size() + " Vulnerabilities."); VulnerabilityComment vulnerabilityComment = null; for (int vulnerabilityId : vulnerabilityCollectionModel.getVulnerabilityIds()) { vulnerabilityComment = new VulnerabilityComment(); vulnerabilityComment.setComment(vulnerabilityCollectionModel.getComment()); vulnerabilityComment.setTags(vulnerabilityCollectionModel.getTags()); vulnerabilityCommentService.addCommentToVuln(vulnerabilityComment, vulnerabilityId); } return RestResponse.success(vulnerabilityComment); }
@Override public void validate(Tag tag, BindingResult result) { Tag databaseTag; if (tag.getName().trim().equals("")) { result.rejectValue("name", null, null, "This field cannot be blank"); } if (containsHTML(tag.getName())) { LOG.error(HTML_ERROR); result.rejectValue("name", null, null, HTML_ERROR); } if (tag.getType() == null) { result.rejectValue("type", null, null, "This field cannot be blank"); } else { // Checking if type is valid TagType type = TagType.getTagType(tag.getType().toString()); databaseTag = loadTagWithType(tag.getName().trim(), type); if (databaseTag != null && (tag.getId() == null || !databaseTag.getId().equals(tag.getId()))) { result.rejectValue("name", MessageConstants.ERROR_NAMETAKEN); } // Check if updating tag is enterprise tag if (tag.getId() != null) { databaseTag = loadTag(tag.getId()); if (databaseTag == null || (databaseTag.getEnterpriseTag() != null && databaseTag.getEnterpriseTag())) { result.rejectValue("name", MessageConstants.ERROR_INVALID, new String[] {"Tag Id"}, null); } } } }
@Override @Transactional(readOnly = false) public void deleteById(int tagId) { LOG.info("Deleting Tag with ID " + tagId); Tag tag = loadTag(tagId); tag.setActive(false); tagDao.saveOrUpdate(tag); }
@RequestMapping(value = "/snapshot/averageAge", method = RequestMethod.POST) public @ResponseBody RestResponse<Map<String, Object>> getPointInTimeAge( @ModelAttribute VulnerabilitySearchParameters reportParameters) throws IOException { long start = System.currentTimeMillis(); log.info("Generating Average Age in Point In Time report"); reportParameters.setShowHidden(false); reportParameters.setShowFalsePositive(false); reportParameters.setShowClosed(false); reportParameters.setShowOpen(true); Map<String, Object> map = vulnerabilitySearchService.generatePointInTimeAgeReport(reportParameters); log.info( "Get Average Age in Point In Time took " + (System.currentTimeMillis() - start) + " ms"); return RestResponse.success(map); }
@RequestMapping(value = "/getTopApps", method = RequestMethod.POST) public @ResponseBody RestResponse<Map<String, Object>> processTopApps( @ModelAttribute VulnerabilitySearchParameters reportParameters, HttpServletRequest request) throws IOException { log.info("Generating Top 20 Vulnerable applications report"); Map<String, Object> map = reportsService.generateMostAppsReport(reportParameters, request); return RestResponse.success(map); }
@RequestMapping(value = "/trendingScans", method = RequestMethod.POST) @JsonView(AllViews.RestViewScanStatistic.class) public @ResponseBody Object processTrendingScans( @ModelAttribute ReportParameters reportParameters, HttpServletRequest request) throws IOException { log.info("Generating trending scans report"); return RestResponse.success(reportsService.generateTrendingReport(reportParameters, request)); }
@RequestMapping(value = "/snapshot/progressByType", method = RequestMethod.POST) public @ResponseBody Object getProgressByType( @ModelAttribute VulnerabilitySearchParameters reportParameters) throws IOException { long start = System.currentTimeMillis(); log.info("Generating Vulnerability Progress By Type report"); reportParameters.setShowHidden(false); reportParameters.setShowFalsePositive(false); reportParameters.setShowClosed(true); reportParameters.setShowOpen(true); List<Object> map = vulnerabilitySearchService.generateProgressByTypeReport(reportParameters); log.info( "Vulnerability Progress By Type report took " + (System.currentTimeMillis() - start) + " ms"); return RestResponse.success(map); }
public RailsEndpointMappings(@Nonnull File rootDirectory) { if (!rootDirectory.exists() || !rootDirectory.isDirectory()) { LOG.error("Root file not found or is not directory. Exiting."); return; } File routesFile = new File(rootDirectory, "/config/routes.rb"); if (!routesFile.exists()) { LOG.error("File /config/routes.rb not found. Exiting."); return; } this.rootDirectory = rootDirectory; routeMap = RailsRoutesParser.parse(routesFile); railsControllers = (List<RailsController>) RailsControllerParser.parse(rootDirectory); this.endpoints = generateMappings(); }
private static void initializeConfiguredFields() { for (Map.Entry<String, Class<? extends AbstractDefectTracker>> entry : recognizedClassMap.entrySet()) { String name = entry.getValue().getName(); if ("false".equals(getProperty(entry.getKey() + ".includeAll"))) { LOG.debug("Not including all fields for " + name + "."); } else { LOG.debug("Including all fields for " + name + "."); INCLUDE_ALL_SET.add(entry.getValue()); } String includedFields = getProperty(entry.getKey() + ".includedFields"); if (includedFields != null) { CONFIGURED_FIELDS.put(entry.getValue(), set(includedFields.split(","))); } } }
@RequestMapping(value = "/{filterId}/deleteChannelFilter", method = RequestMethod.POST) @JsonView(AllViews.TableRow.class) public @ResponseBody RestResponse<String> submitDeleteChannelFilter(@PathVariable int filterId) { if (!EnterpriseTest.isEnterprise()) { String msg = "You do not have permission to delete channel vulnerability filter. You need to update to enterprise license."; log.warn(msg); return RestResponse.failure(msg); } return RestResponse.success(submitDeleteChannelFilterBackend(filterId)); }
@RequestMapping(value = "/snapshot", method = RequestMethod.POST) @JsonView(AllViews.VulnSearchApplications.class) public @ResponseBody RestResponse<Map<String, Object>> processSnapShot( @ModelAttribute ReportParameters reportParameters, HttpServletRequest request) throws IOException { log.info("Generating snapshot report"); Map<String, Object> map = reportsService.generateSnapshotReport(reportParameters, request); map.put("tags", tagService.loadAllApplicationTags()); map.put("vulnTags", tagService.loadAllVulnTags()); return RestResponse.success(map); }
@Override public boolean isValidTags(List<Tag> allTags, List<Tag> tags) { for (Tag tag : tags) { if (!containTag(allTags, tag)) { LOG.warn("Tag ID " + tag.getId() + " is invalid."); return false; } } return true; }
@Override public void updateTagTypes() { LOG.info("About to update type for all tags."); for (Tag tag : tagDao.retrieveAll()) { if (!tag.getTagForComment()) { // this is an application tag tag.setType(TagType.APPLICATION); } else { tag.setType(TagType.COMMENT); } tagDao.saveOrUpdate(tag); } }
@Override public void copyAppTagsToCommentTags() { List<Tag> appTags = loadAllApplicationTags(); if (appTags == null) { LOG.info("There is no tags in system."); return; } LOG.info("About to copy " + appTags.size() + " application tags to comment tags."); for (Tag appTag : appTags) { if (loadCommentTag(appTag.getName()) == null) { LOG.info("Copying " + appTag.getName()); Tag newCommentTag = new Tag(); newCommentTag.setName(appTag.getName()); newCommentTag.setEnterpriseTag(appTag.getEnterpriseTag()); newCommentTag.setDefaultJsonFilter(appTag.getDefaultJsonFilter()); newCommentTag.setType(TagType.COMMENT); tagDao.saveOrUpdate(newCommentTag); } appTag.setType(TagType.APPLICATION); tagDao.saveOrUpdate(appTag); } }
@RequestMapping(value = "/newChannelFilter", method = RequestMethod.POST) @JsonView(AllViews.TableRow.class) public @ResponseBody RestResponse<ChannelVulnerabilityFilter> submitNewChannelFilter( ChannelVulnerabilityFilter channelVulnerabilityFilter, BindingResult bindingResult, SessionStatus status) { if (!EnterpriseTest.isEnterprise()) { String msg = "You do not have permission to add new channel vulnerability filter. You need to update to enterprise license."; log.warn(msg); return RestResponse.failure(msg); } return submitNewChannelFilterBackend(channelVulnerabilityFilter, bindingResult, status); }
public static File getScratchFile(String path) { if (path == null) { throw new IllegalArgumentException("Null path passed to getScratchFile()"); } LOG.debug("getScratchFile << " + path); final File returnFile; String root = getRootPath(); if (root == null) { LOG.debug("Scratch folder is not configured, using relative path."); returnFile = new File(path); } else { File file = new File(root); if (!file.exists()) { LOG.error( "Supplied scratch location (" + root + ") didn't exist. Defaulting to relative path."); returnFile = new File(path); } else if (!file.isDirectory()) { LOG.error( "Supplied scratch location (" + root + ") is not a directory. Defaulting to relative path."); returnFile = new File(path); } else if (!file.canWrite()) { LOG.error( "ThreadFix is unable to write to the supplied scratch location (" + root + "). Defaulting to relative path."); returnFile = new File(path); } else { LOG.debug("Got a valid scratch root from system properties."); String canonicalRoot = file.getAbsolutePath(); boolean hasSlash = canonicalRoot.endsWith(File.separator) || path.startsWith(File.separator); if (hasSlash) { returnFile = new File(canonicalRoot + path); } else { returnFile = new File(canonicalRoot + File.separator + path); } } } LOG.debug("getScratchFile >> " + returnFile.getAbsolutePath()); return returnFile; }
public static long getAvailableDiskSpace() { File tmp = getScratchFile("tmp"); try { if (!tmp.exists()) { tmp.createNewFile(); } return tmp.getUsableSpace(); } catch (IOException e) { throw new RestIOException(e, "Unable to store temporary file."); } finally { if (tmp.exists()) { boolean deletedTempFile = tmp.delete(); if (!deletedTempFile) { LOG.error("Unable to delete temporary file at " + tmp.getAbsolutePath()); } } } }
public static List<DynamicFormField> getFields(String jsonString, UserRetriever retriever) { LOG.debug("Starting JSON field description deserialization."); try { ObjectMapper objectMapper = getLenientObjectMapper(); JiraJsonMetadataResponse response = objectMapper.readValue(jsonString, JiraJsonMetadataResponse.class); if (response.projects.size() == 0) { throw new IllegalStateRestException( "No projects were found. " + "Bad permissions can cause this error. Please check your configuration."); } assert response.projects.size() == 1 : "The response contained more than one project. Something went wrong."; Project project = response.getProjectOrNull(); List<DynamicFormField> fieldList = list(); if (project != null) { DynamicFormField issueTypeField = new DynamicFormField(); issueTypeField.setRequired(true); issueTypeField.setName("issuetype"); issueTypeField.setLabel("Issue Type"); issueTypeField.setActive(true); issueTypeField.setEditable(true); issueTypeField.setType("select"); Map<String, String> issueTypeValuesMap = map(); addField(issueTypeField, fieldList, null); Set<String> timetrackingSet = set(); for (IssueType issueType : project.getIssuetypes()) { issueTypeValuesMap.put(issueType.getId(), issueType.getName()); for (Map.Entry<String, Field> entry : issueType.getFields().entrySet()) { Field jsonField = entry.getValue(); String type = jsonField.getSchema().getType(); if ("issuelink".equals(type)) type = "string"; if ("array".equals(type) && "attachment".equals(jsonField.getSchema().getItems())) { continue; // you can't make attachments required and we don't support uploads. } DynamicFormField field = new DynamicFormField(); field.setShow("issuetype=" + issueType.getId()); field.setRequired(jsonField.isRequired()); field.setName(entry.getKey()); field.setLabel(jsonField.getName()); field.setActive(true); field.setEditable(true); if (jsonField.getAllowedValues() != null && !jsonField.getAllowedValues().isEmpty()) { if (MULTISELECT.equals(jsonField.getSchema().getCustom())) { field.setSupportsMultivalue(true); } if (MULTI_CHECKBOX.equals(jsonField.getSchema().getCustom())) { field.setSupportsMultivalue(true); field.setType("checklist"); } else if (CASCADING_SELECT.equals(jsonField.getSchema().getCustom())) { field.setType("select"); } else { field.setType("select"); } field.setOptionsMap(jsonField.getOptionsMap()); } else if (type.equals("timetracking")) { LOG.debug("Adding timetracking fields (x2)"); if (timetrackingSet.contains(entry.getKey())) { continue; // otherwise we will have duplicates } else { timetrackingSet.add(entry.getKey()); } DynamicFormField originalEstimate = new DynamicFormField(); originalEstimate.setRequired(jsonField.isRequired()); originalEstimate.setName("timetracking_originalestimate"); originalEstimate.setLabel("Original Estimate"); originalEstimate.setActive(true); originalEstimate.setEditable(true); originalEstimate.setValidate(TIMETRACKING_REGEX); originalEstimate.setType("text"); originalEstimate.setPlaceholder(PLACEHOLDER_TEXT); originalEstimate.setError("pattern", TIMETRACKING_ERROR); fieldList.add(originalEstimate); DynamicFormField remainingEstimate = new DynamicFormField(); remainingEstimate.setRequired(jsonField.isRequired()); remainingEstimate.setName("timetracking_remainingestimate"); remainingEstimate.setLabel("Remaining Estimate"); remainingEstimate.setActive(true); remainingEstimate.setValidate(TIMETRACKING_REGEX); remainingEstimate.setPlaceholder(PLACEHOLDER_TEXT); remainingEstimate.setEditable(true); remainingEstimate.setType("text"); remainingEstimate.setError("pattern", TIMETRACKING_ERROR); fieldList.add(remainingEstimate); continue; } else if (type.equals("string")) { if (URL_TYPE.equals(jsonField.getSchema().getCustom())) { field.setType("url"); } else if (TEXTAREA_TYPE.equals(jsonField.getSchema().getCustom())) { field.setType("textarea"); } else { field.setType("text"); } } else if (type.equals("number")) { if (FLOAT_TYPE.equals(jsonField.getSchema().getCustom())) { field.setValidate(FLOAT_REGEX); field.setType("text"); field.setError("pattern", "Must be float format (ex. 3.14)"); } else { field.setType("number"); } } else if (type.equals("date") || type.equals("datetime")) { field.setType("date"); } else if (type.equals("array") && jsonField.getSchema().getItems().equals("string")) { field.setType("text"); field.setSupportsMultivalue(true); } else if (type.equals("user")) { field.setType("select"); Map<String, String> map = retriever.getUserMap(); if (map == null) { field.setType("text"); } else field.setOptionsMap(map); } else if (type.equals("array")) { LOG.error( "Unable to determine dynamic type for " + entry.getKey() + ":" + type + " of " + jsonField.getSchema().getItems()); field.setType("select"); } LOG.debug( "Adding new field with label " + field.getLabel() + " and type " + field.getType()); addField(field, fieldList, issueTypeField); } } issueTypeField.setOptionsMap(issueTypeValuesMap); } return fieldList; } catch (IOException e) { LOG.error("Failed to deserialize JSON."); LOG.debug("Failing JSON: " + jsonString, e); throw new RestIOException(e, "Unable to parse server response."); } }