Package com.denimgroup.threadfix.service

Source Code of com.denimgroup.threadfix.service.FindingServiceImpl

////////////////////////////////////////////////////////////////////////
//
//     Copyright (c) 2009-2014 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.service;

import com.denimgroup.threadfix.data.dao.*;
import com.denimgroup.threadfix.data.entities.*;
import com.denimgroup.threadfix.importer.util.IntegerUtils;
import com.denimgroup.threadfix.logging.SanitizedLogger;
import com.denimgroup.threadfix.service.beans.TableSortBean;
import com.denimgroup.threadfix.webapp.controller.rest.AddFindingRestController;
import com.denimgroup.threadfix.webapp.utils.MessageConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.PathVariable;

import javax.annotation.Nonnull;
import javax.servlet.http.HttpServletRequest;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import static com.denimgroup.threadfix.CollectionUtils.list;

@Service
@Transactional(readOnly = false) // used to be true
public class FindingServiceImpl implements FindingService {

  private FindingDao findingDao = null;
  private ChannelVulnerabilityDao channelVulnerabilityDao = null;
  private GenericVulnerabilityDao genericVulnerabilityDao = null;
  private UserDao userDao = null;
  private ChannelTypeDao channelTypeDao = null;
  private ChannelSeverityDao channelSeverityDao = null;

  private final SanitizedLogger log = new SanitizedLogger(FindingServiceImpl.class);
 
  @Autowired
  public FindingServiceImpl(FindingDao findingDao,
      ChannelSeverityDao channelSeverityDao,
      ChannelVulnerabilityDao channelVulnerabilityDao,
      GenericVulnerabilityDao genericVulnerabilityDao,
      ChannelTypeDao channelTypeDao, UserDao userDao) {
    this.findingDao = findingDao;
    this.channelTypeDao = channelTypeDao;
    this.channelSeverityDao = channelSeverityDao;
    this.userDao = userDao;
    this.genericVulnerabilityDao = genericVulnerabilityDao;
    this.channelVulnerabilityDao = channelVulnerabilityDao;
  }
 
  @Override
  public void validateManualFinding(Finding finding, BindingResult result, boolean isStatic) {
   
   
    if (finding == null || ((finding.getChannelVulnerability() == null) ||
        (finding.getChannelVulnerability().getCode() == null) ||
        (finding.getChannelVulnerability().getCode().isEmpty()))) {
      result.rejectValue("channelVulnerability.code", "errors.required", new String [] { "Vulnerability" }, null);
    } else {
            String code = finding.getChannelVulnerability().getCode();
            if (code.indexOf("(CWE")<0)
                finding.getChannelVulnerability().setCode(code.trim());
            else finding.getChannelVulnerability().setCode(code.substring(0, code.indexOf("(CWE")).trim());

            if (!channelVulnerabilityDao.isValidManualName(finding.getChannelVulnerability().getCode())) {

        boolean wasNumeric = false;

        // Try to parse an ID from the string and use that
        ChannelVulnerability newChannelVuln = null;

                Integer requestedId = IntegerUtils.getIntegerOrNull(finding.getChannelVulnerability().getCode());

                if (requestedId != null) {
                    wasNumeric = true;
                    String cweName = null;
                    ChannelType manualType = null;
                    GenericVulnerability genericVulnerability = genericVulnerabilityDao.retrieveByDisplayId(requestedId);
                    if (genericVulnerability != null) {
                        cweName = genericVulnerability.getName();
                        if (cweName != null) {
                            manualType = channelTypeDao.retrieveByName(ScannerType.MANUAL.getFullName());
                            if (manualType != null) {
                                newChannelVuln = channelVulnerabilityDao.retrieveByName(manualType, cweName);
                            }
                        }
                    }

                    if (newChannelVuln != null) {
                        // id lookup success, set the name to the actual name instead of the id.
                        finding.getChannelVulnerability().setCode(newChannelVuln.getCode());
                    }
                }

        if (newChannelVuln == null) {
          // ID lookup failed
          if (wasNumeric) {
            result.rejectValue("channelVulnerability.code", null, null, "The supplied ID was invalid." +
                " Please enter a valid CWE name or ID from http://cwe.mitre.org/");
          } else {
            result.rejectValue("channelVulnerability.code", null, null, "The supplied name was invalid. " +
                "Please enter a valid CWE name or ID (example: 79) from http://cwe.mitre.org/");
          }
        }
      }
    }

    if (finding != null && (finding.getLongDescription() == null ||
        finding.getLongDescription().trim().isEmpty())) {
      result.rejectValue("longDescription", "errors.required", new String [] { "Description" }, null);
    }

    FieldError originalError = result.getFieldError("dataFlowElements[0].lineNumber");
    if (originalError != null && originalError.getDefaultMessage()
        .startsWith("Failed to convert property value of type " +
            "'java.lang.String' to required type 'int'")) {
      result.rejectValue("dataFlowElements", "errors.invalid", new String [] { "Line number" }, null);
    }

        if (isStatic && (finding.getSurfaceLocation() == null
                || finding.getSurfaceLocation().getParameter() == null
                || finding.getSurfaceLocation().getParameter().trim().isEmpty())) {
            result.rejectValue("surfaceLocation.parameter", MessageConstants.ERROR_REQUIRED, new String [] { "Parameter" }, null);
        } else if (!isStatic) {
            if (finding.getSurfaceLocation() == null ||
                    ( (finding.getSurfaceLocation().getParameter() == null || finding.getSurfaceLocation().getParameter().trim().isEmpty()) &&
                            (finding.getSurfaceLocation().getPath() == null || finding.getSurfaceLocation().getPath().trim().isEmpty()) )) {
                result.rejectValue("surfaceLocation.parameter", null, null, "Input at least URL or Parameter");
            }
        }
  }

  @Override
  public List<Finding> loadAll() {
    return findingDao.retrieveAll();
  }

  @Override
  public Finding loadFinding(int findingId) {
    return findingDao.retrieveById(findingId);
  }
 
  @Override
  public List<String> loadSuggested(String hint, int appId) {
    return findingDao.retrieveByHint(hint, appId);
  }
 
  @Override
  public List<Finding> loadLatestStaticByAppAndUser(int appId, int userId) {
    return findingDao.retrieveLatestStaticByAppAndUser(appId, userId);
  }
 
  @Override
  public List<Finding> loadLatestDynamicByAppAndUser(int appId, int userId) {
    return findingDao.retrieveLatestDynamicByAppAndUser(appId, userId);
  }

  @Override
  @Transactional(readOnly = false)
  public void storeFinding(Finding finding) {
    findingDao.saveOrUpdate(finding);
  }
 
  @Override
  public Finding parseFindingFromRequest(HttpServletRequest request) {
    String staticParameter = request.getParameter("isStatic");
    boolean isStatic = staticParameter != null && staticParameter.equals("true");
   
    Finding finding = new Finding();
    SurfaceLocation location = new SurfaceLocation();
    ChannelSeverity channelSeverity = new ChannelSeverity();
    ChannelVulnerability channelVulnerability = new ChannelVulnerability();
       
    finding.setSurfaceLocation(location);
       
    String vulnType = request.getParameter("vulnType");
    channelVulnerability.setCode(vulnType);
    finding.setChannelVulnerability(channelVulnerability);
   
    String longDescription = request.getParameter("longDescription");
    if (longDescription != null && !longDescription.trim().equals("") &&
        longDescription.length() < Finding.LONG_DESCRIPTION_LENGTH) {
      finding.setLongDescription(longDescription);
    }
   
    String severity = request.getParameter("severity");
    channelSeverity.setId(IntegerUtils.getPrimitive(severity));
    finding.setChannelSeverity(channelSeverity);
   
    String nativeId = request.getParameter("nativeId");
    if (nativeId != null && nativeId.length() < Finding.NATIVE_ID_LENGTH) {
      finding.setNativeId(nativeId);
    }
   
    String parameter = request.getParameter("parameter");
    if (parameter != null && parameter.length() < SurfaceLocation.PARAMETER_LENGTH) {
      location.setParameter(parameter);
    }
   
    if (isStatic) {
      log.info("The 'static' parameter was set to 'true', a static finding is being created.");
      String filePath = request.getParameter("filePath");
      String column = request.getParameter("column");
      String lineText = request.getParameter("lineText");
      String lineNumber = request.getParameter("lineNumber");
     
      finding.setIsStatic(true);
     
      DataFlowElement element = new DataFlowElement(filePath, IntegerUtils.getPrimitive(lineNumber), lineText, 0);
      element.setColumnNumber(IntegerUtils.getPrimitive(column));
      finding.setDataFlowElements(new ArrayList<DataFlowElement>());
      finding.getDataFlowElements().add(element);
    } else {
      log.info("The 'static' parameter was not present or not 'true'," +
          " a dynamic finding is being created.");
     
      String fullUrl = request.getParameter("fullUrl");
      location.setUrl(getUrl(fullUrl));
      String path = request.getParameter("path");
      if (path != null) {
        location.setPath(path);
      }
    }
   
    return finding;
  }
 
  /**
   *
   */
    @Nonnull
    public String checkRequestForFindingParameters(@Nonnull HttpServletRequest request) {
    String longDescription = request.getParameter("longDescription");
    if (longDescription == null || longDescription.trim().equals("") ||
        longDescription.length() > Finding.LONG_DESCRIPTION_LENGTH) {
      return AddFindingRestController.INVALID_DESCRIPTION;
    }
   
    String vulnType = request.getParameter("vulnType");
    ChannelVulnerability channelVulnerability = null;
    if (vulnType != null) {
      channelVulnerability = channelVulnerabilityDao
        .retrieveByCode(
            channelTypeDao.retrieveByName(ScannerType.MANUAL.getFullName()),
            vulnType);
    }
   
    if (vulnType == null || channelVulnerability == null) {
      return AddFindingRestController.INVALID_VULN_NAME;
    }
   
    return AddFindingRestController.PASSED_CHECK;
  }
 
  /**
   * This method just wraps the try / catch MalformedURLException of URL()
   * to ease String parsing.
   * @param possibleURL
   * @return
   */
  private URL getUrl(String possibleURL) {
    try {
      return new URL(possibleURL);
    } catch (MalformedURLException e) {
      log.warn("Tried to parse a URL out of a user-supplied String but failed.");
    }
   
    return null;
  }
 
 
  @Override
  public List<Finding> getFindingTable(Integer scanId, TableSortBean bean) {
    return findingDao.retrieveFindingsByScanIdAndPage(scanId, bean.getPage());
  }

  @Override
  public Object getUnmappedFindingTable(Integer scanId, TableSortBean bean) {
    return findingDao.retrieveUnmappedFindingsByScanIdAndPage(scanId, bean.getPage());
  }

  @Override
  public List<Finding> getUnmappedFindingTable(TableSortBean bean) {
    return findingDao.retrieveUnmappedFindingsByPage(bean.getPage(), bean.getApplicationId());
  }

  @Override
  public List<String> getRecentStaticVulnTypes(@PathVariable("appId") int appId){
    String userName = SecurityContextHolder.getContext().getAuthentication().getName();
    Integer userId = null;
    User user = userDao.retrieveByName(userName);
    if (user != null)
      userId = user.getId();
    if (userName == null || userId == null)
      return null;
    List<Finding> findings = loadLatestStaticByAppAndUser(appId, userId);
    if(findings == null) return null;
    List<String> cvList = list();
    for(Finding finding : findings) {
      if (finding == null || finding.getChannelVulnerability() == null ||
          finding.getChannelVulnerability().getCode() == null)
        continue;
      cvList.add(finding.getChannelVulnerability().getCode());
    }
    return removeDuplicates(cvList);
  }
 
  @Override
  public List<String> getRecentDynamicVulnTypes(@PathVariable("appId") int appId){
    String userName = SecurityContextHolder.getContext().getAuthentication().getName();
    Integer userId = null;
    User user = userDao.retrieveByName(userName);
    if (user != null)
      userId = user.getId();
    if (userName == null || userId == null)
      return null;
    List<Finding> findings = loadLatestDynamicByAppAndUser(appId, userId);
    if(findings == null) return null;
    List<String> cvList = list();
    for(Finding finding : findings) {
      if (finding == null || finding.getChannelVulnerability() == null ||
          finding.getChannelVulnerability().getCode() == null)
        continue;
      cvList.add(finding.getChannelVulnerability().getCode());
    }
    return removeDuplicates(cvList);
  }
 
  @Override
  public List<String> getRecentStaticPaths(@PathVariable("appId") int appId) {
    String userName = SecurityContextHolder.getContext().getAuthentication().getName();
    Integer userId = null;
    User user = userDao.retrieveByName(userName);
    if (user != null)
      userId = user.getId();
    if (userName == null || userId == null)
      return list();
    List<Finding> findings = loadLatestStaticByAppAndUser(appId, userId);
    if(findings == null) return null;
    List<String> pathList = list();
    for(Finding finding : findings) {
      if (finding == null || finding.getSurfaceLocation() == null ||
          finding.getSurfaceLocation().getPath() == null)
        continue;
      pathList.add(finding.getSurfaceLocation().getPath());
    }
    return removeDuplicates(pathList);
  }
 
  @Override
  public List<String> getRecentDynamicPaths(@PathVariable("appId") int appId) {
    String userName = SecurityContextHolder.getContext().getAuthentication().getName();
    Integer userId = null;
    User user = userDao.retrieveByName(userName);
    if (user != null)
      userId = user.getId();
    if (userName == null || userId == null)
      return list();
    List<Finding> findings = loadLatestDynamicByAppAndUser(appId, userId);
    if(findings == null) return null;
    List<String> pathList = list();
    for(Finding finding : findings) {
      if (finding == null || finding.getSurfaceLocation() == null ||
          finding.getSurfaceLocation().getPath() == null)
        continue;
      pathList.add(finding.getSurfaceLocation().getPath());
    }
    return removeDuplicates(pathList);
  }
 
  private List<String> removeDuplicates(List<String> stringList) {
    if (stringList == null)
      return list();
    List<String> distinctStringList = list();
    for (int i = 0; i < stringList.size(); i++) {
      int j = 0;
      for (; j < i; j++) {
        if (stringList.get(i).equals(stringList.get(j))) {
          break;
        }
      }
      if (j == i)
        distinctStringList.add(stringList.get(i));
    }
    return distinctStringList;
  }
 
  @Override
  public List<ChannelSeverity> getManualSeverities() {
    ChannelType channelType = channelTypeDao.retrieveByName(ScannerType.MANUAL.getFullName());
    return channelSeverityDao.retrieveByChannel(channelType);
  }

  @Override
  public List<String> getAllManualUrls(Integer appId) {
    return findingDao.retrieveManualUrls(appId);
  }
}
TOP

Related Classes of com.denimgroup.threadfix.service.FindingServiceImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.