// 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.");
  }
예제 #2
0
 @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);
   }
 }
예제 #3
0
  @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);
  }
예제 #7
0
  @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);
        }
      }
    }
  }
예제 #8
0
 @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);
 }
예제 #9
0
  @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);
  }
예제 #10
0
 @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);
 }
예제 #11
0
 @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));
 }
예제 #12
0
  @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));
 }
예제 #16
0
 @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);
 }
예제 #17
0
  @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;
  }
예제 #18
0
 @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);
   }
 }
예제 #19
0
 @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);
 }
예제 #21
0
  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;
  }
예제 #22
0
  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.");
    }
  }